NPM Implements Pre-Publication Malware Scanning, But Will It Work? | OpenSourceMalware
On July 28, npm announced publish-time malware scanning. New packages get scanned before they become installable, and depending on what the scanner finds, a package is published normally, held for manual review, or blocked outright. I want to say up front that I’m genuinely happy about this. Stopping malware before it reaches a developer’s machine is better than pulling it down afterwards, and it’s the change I’ve wanted from npm for years.<br>Then I read the announcement again. It’s 447 words. It doesn’t say what the scanner is. It doesn’t say when this starts. It doesn’t say whether they’ve partnered with anyone. It doesn’t give a single number about how well any of it works. And most importantly, it doesn’t mention that npm has been scanning every package version on the registry this entire time — which is a fact npm published themselves, four months ago.<br>What NPM actually announced<br>The mechanics are straightforward. Publishing now introduces a delay of about five minutes before your package is installable, stretching to 15 minutes or more at peak times or for larger packages. NPM is careful to say those numbers “aren’t a service guarantee.” While a publish is pending, npm dist-tag still works, but npm deprecate and npm unpublish don’t. If your CI assumes a package is installable the instant npm publish returns, that’s now broken and you need to fix it.<br>If a package gets blocked, the publisher “may receive a notification with the option to appeal.” Depending on the severity and confidence of the finding, NPM may also take action against the maintainer account.<br>The second half of the announcement introduces something new: a contentPolicy field in package.json for declaring what NPM calls dual-use content. Packages that declare it must also ship a text-only DISCLOSURE file in the package root explaining the functionality and its legitimate use. Dual-use packages have to be published through a method that enforces 2FA, and once you’ve declared it you can never take it back — new versions that drop the field or the file get rejected. NPM says this will be “progressively enforced” and that they’re emailing maintainers of dual-use packages directly so they don’t get blocked by default.<br>Gating on publish is the correct architecture, full stop.<br>For as long as I’ve been doing this, unfortunately the model has been publish-first, catch-later. A malicious package goes live, it gets installed by real people for somewhere between six minutes and six weeks, someone reports it, and eventually it comes down. Every incident we document at OpenSourceMalware lives inside that window. The window is the damage. A malicious package that never becomes installable has a blast radius of zero, and no amount of downstream tooling gets you that.<br>This is also the one piece of the puzzle that only the registry can do. Cooldowns, package firewalls, and lockfile discipline are all attempts by the rest of us to build a filter in front of a registry that ships whatever it’s handed. npm putting the filter where it belongs — at the front door, on their side of it — is a structurally better answer than any of them. I don’t want to be cynical about that. It’s the right change.<br>NPM has been scanning since at least April 2026<br>But here's what the announcement leaves out. On April 1, 2026 in a post about securing the open source supply chain, GitHub Principal Engineer Zachary Steindler wrote:<br>“We scan every npm package version for malware, and our detections are constantly updated and improved as attacks evolve. Hundreds of newly published packages contain malicious code daily, so when detected, a human reviews to confirm it’s a true positive before we take action. At this scale, even a 1% false-positive rate would disrupt hundreds of legitimate publishes daily.”
Read that next to the July announcement and the shape of this thing changes completely. This is not npm starting to scan for malware. This is npm moving a scan it was already running to the other side of the publish gate. The detection engine is the same engine. The rules are the same rules. The only thing that moved is when the answer gets applied.<br>That matters because we already know how well that engine performs. Sonatype has logged roughly 1.8 million malicious packages, and npm accounted for 96.6% of the malicious package count in Q2 2026 alone — somewhere around 46 malicious npm packages a day earlier in the year. The IndonesianFoods campaign pushed more than 150,000 malicious packages into the registry over a couple of days in 2025. Shai-Hulud landed. Mini Shai-Hulud landed. Miasma landed. Every one of those happened on a registry that was, by its own account, scanning every package version for malware. And today we know that there are literally of thousands of known malicious packages sitting in npm that credible researchers reported, yet still haven't been taken down.<br>So when npm says a...