Goal
Introduce a reusable malware-scanning boundary that examines uploaded package bytes before any artifact or version metadata becomes installable.
Context
npm now scans newly published packages before availability and may allow, hold, or block a publish: https://github.blog/changelog/2026-07-28-npm-publish-time-malware-scanning-and-dual-use-metadata/
Pantry currently validates identity, metadata, size, and duplicate versions, then persists the tarball immediately. It does not inspect uploaded content for malware.
Scope
- Define a scanner interface and stable verdict model:
clean,review,blocked, anderror. - Provide a production ClamAV/clamd implementation using the INSTREAM protocol, with timeouts and bounded responses.
- Compute a scan identifier/hash and capture engine/signature/version/timing metadata.
- Fail closed when scanning is required but unavailable or times out.
- Make development/test behavior explicit and injectable; never silently disable production scanning.
- Bound archive size, decompression behavior, scanner response size, and network time.
- Avoid logging tarball content, tokens, or sensitive disclosure text.
Acceptance criteria
- Clean EICAR-free fixtures return
clean. - EICAR fixtures return
blockedwith the signature name. - Scanner outage and timeout return a non-success verdict and do not publish.
- Configuration is environment-driven and validated at startup/request time.
- Unit tests cover protocol framing, partial TCP responses, limits, timeouts, and malformed responses.
- The implementation has no external paid-service dependency.
Non-goals
- Replacing a full antivirus signature feed with handwritten heuristics.
- Executing uploaded package lifecycle scripts.
- Allowing a scanner outage to publish unscanned artifacts.