Requires a clean scanner verdict before uploaded objects become downloadable, quarantines failed or timed-out scans, and defines containment and re-scan steps for a suspected scanner compromise.
Package status: reference context ready for human review. The contract and test scenarios are complete, but no claim is made that an adopting implementation has passed them.
Decision
An uploaded object is not downloadable until a named scanner returns a clean verdict bound to that object's content digest. Failed scans, timeouts, engine errors, and unscannable oversize results quarantine the object. Scanner hosts, credentials, and network paths stay isolated to limit blast radius. Identity authentication and digest binding prevent callback mix-ups and unauthorized verdict injection, but they do not prove that a compromised scanner inspected the bytes correctly; compromise therefore triggers revocation, a serving freeze for the affected verdict window, and re-scan by a trusted replacement engine.
Scope
- Upload completion, pending-scan storage, verdict authentication, quarantine, download authorization, owner-visible scan status, operator destroy, and scanner isolation for user-uploaded bytes.
- Authenticated product upload APIs that persist tenant objects.
- Re-scan of quarantined objects after signature-pack updates.
Outside this block
- Scanning of first-party static assets baked into application images.
- Workstation antivirus on operator laptops.
Contract
- After upload completes, bytes exist only under a pending-scan or quarantine key; download and signed-URL issuance return a scan-pending or scan-blocked error until a clean verdict is recorded.
- A clean verdict is accepted only from the configured scanner identity, cites the object digest, and stores timestamp plus engine version.
- Infected, timeout, error, and unscannable-oversize verdicts quarantine the object; range and full downloads of those keys are refused.
- Scanner hosts cannot write serving prefixes; they return verdicts on an authenticated channel and read only the object under inspection.
- When the scan budget expires, the object is quarantined rather than served.
- Declared or suspected scanner compromise revokes that workload identity and freezes serving for objects whose only clean verdict falls inside the affected window; those objects remain unavailable until a trusted replacement engine re-scans them.
Implementation guidance
- Complete the multipart or resumable upload into a non-public prefix, enqueue a scan job with digest and size, and flip serving keys only after clean.
- Authenticate scanner callbacks with workload identity or mutual TLS; reject unsigned or replayed verdicts. Treat this as channel authentication, not attestation that a compromised engine behaved correctly.
- For higher-assurance upload classes, require independent engines or verifiable scanner attestation as an adoption control rather than assuming network isolation supplies that assurance.
Failure handling
- Scanner timeout, crash, or HTTP 5xx is a fail-closed quarantine, not a pass.
- Duplicate verdicts for the same digest must match; a later clean after infected requires an operator override with audit.
- On compromise, define the earliest credible compromise time, mark affected clean verdicts suspect, revoke credentials, isolate the workload, and re-scan with an independently trusted engine before restoring downloads.
Verification and operations
- Measure pending age, quarantine rate, timeout rate, download-block counts, and scanner identity mismatches.
- Alert when pending objects exceed the soak budget or when clean verdicts arrive from an unknown identity.
- Prove with tests that a pending object cannot be fetched by a valid user session or a leaked object key.
The executable-looking examples in this package are fixtures and acceptance contracts. Run
python tools/validate.py from the collection root to check package structure and metadata; then
implement and execute the scenarios in the target repository.
Adoption assumptions
- Names and numeric values in
example.yamlare an adoption profile, not universal defaults. - The adopting team must map actors, data classes, error vocabulary, and ownership to its system.