The September 2025 npm supply-chain incident gave the security community an unusually clean view of registry-side response performance. AWS's December 2025 blog post on what its security team learned from the incident publishes specific measurements: the September 8 compromise of chalk, debug, and 16 other packages was removed from the registry roughly 2.5 hours after the malicious versions were published. The Shai-Hulud 2.0 wave in November, with significantly larger blast radius, was contained in roughly 12 hours. AWS reports that its own internal response process began within 7 minutes of the publish event because of automated monitoring against the OpenSSF malicious-packages feed. This post walks through how the registry-side workflow operates, how downstream consumers should be reading the signal, and what policy gates close the loop on the residual risk during the response window.
What is the actual npm takedown workflow?
A typical malicious-publish takedown moves through six steps. Step one is detection, which today is overwhelmingly third-party rather than registry-internal: Socket, ReversingLabs, Phylum, Snyk, JFrog, and AWS all run continuous scanning against new npm publishes, and one of them usually files the first report. Step two is verification by the npm security team or by GitHub's broader trust and safety apparatus. Step three is removal of the malicious versions and, in some cases, the entire affected package if the maintainer account is fully compromised. Step four is registration of the affected versions in the OpenSSF malicious-packages repository, giving every downstream consumer a single feed to read. Step five is maintainer notification and credential revocation: any tokens issued to the compromised account are invalidated, any associated 2FA enrollments are reviewed, and the maintainer is contacted via verified channels. Step six is the public advisory, posted either on the GitHub Security Lab blog or via a community discussion thread.
How did the response time actually compress so far?
Three factors moved the needle between earlier incidents and the 2025 waves. The first is OpenSSF malicious-packages as a shared coordination layer. Before 2024, each scanning vendor maintained its own private feed and the registry team had to manually correlate reports. The shared repository gives every responder a single place to push verified-malicious entries, and downstream consumers a single place to subscribe. The second is the maturation of automated unpublish flows on the npm side; in 2022 takedowns required a manual operator action, while in 2025 a verified malicious-package signal can flow through a privileged automation path with human approval in minutes rather than hours. The third is cross-cloud coordination: AWS's blog post explicitly describes its security team registering compromised packages with OpenSSF "within 7 minutes of publication," which feeds the registry team's own queue in close to real time.
What does the signal look like for downstream consumers?
A consuming organization sees the takedown through three channels. The first is the registry itself: the affected version disappears from https://registry.npmjs.org/<name> and an attempt to install it returns a 404. The second is the OpenSSF malicious-packages feed, which adds an entry tagged with the package, the affected version range, and the report source. The third is the dependency review on the consuming side: tools like Dependabot, npm audit, Snyk, and Socket pick up the OpenSSF signal and produce findings in your environment. The window between publish and removal is the residual risk: any install that happened during that 2.5-to-12-hour window may have pulled malicious code, and the response work for consumers is to identify those installs after the fact.
How do you verify and respond in CI?
The defender pattern is to (a) shrink the install-window risk through a soak policy on new versions and (b) make post-hoc identification fast when the soak fails. The first part is a policy gate; the second is a query against your build history.
# Subscribe to the OpenSSF malicious-packages feed and fail builds
# on any lockfile entry that matches a confirmed-bad entry within
# a configurable lookback window
git clone --depth=1 https://github.com/ossf/malicious-packages /tmp/mal
node tools/check-lockfile-against-feed.js \
--feed /tmp/mal \
--lock package-lock.json \
--ecosystem npm \
--lookback-hours 72
# Identify which prior builds resolved a version that is now flagged
npm view <pkg>@<bad-version> dist.tarball
grep -F "<tarball-sha>" /var/log/ci/build-history.log
The --ignore-scripts flag during install closes the most damaging surface of Shai-Hulud-class worms: the malicious code in the September wave executed during the npm postinstall lifecycle and exfiltrated runner credentials. A CI policy that runs npm ci --ignore-scripts for any new or upgraded dependency, and only runs lifecycle scripts inside a separate hardened step for an allow-list of trusted packages, would have neutralized the worm's propagation path entirely.
What policy gate catches the next wave going forward?
Three gates align with the registry-side response timeline. Gate one is a soak window: do not install a new version of any top-1000 dependency for the first N hours after publish, where N is sized larger than the empirical takedown window (24-72 hours is conservative). Gate two is --ignore-scripts by default, with explicit per-package allow-lists for the small set of dependencies that genuinely require postinstall hooks. Gate three is OpenSSF malicious-packages feed integration with a lookback that covers your full build retention window, so when a takedown happens 8 hours after a build, you can still identify whether your build was in the affected install window. The combination roughly halves the residual exposure for organizations that adopt all three.
What did the response also teach about communication?
The 2025 incidents made the comms workflow more visible than usual. CISA published the September advisory titled "Widespread Supply Chain Compromise Impacting npm Ecosystem" within 48 hours, naming affected packages and giving consuming organizations a citable source for internal coordination. PyPI published its parallel advisory on November 26 noting credential leakage from compromised GitHub repos. AWS, OpenAI, and Elastic all published internal-response retrospectives between October 2025 and February 2026, which collectively form an unusually rich set of "how we did it" comparators that defenders can crib from. The Securing Software Repositories WG hosted cross-registry calls during both waves, sharing IoCs and coordinating wording so consuming organizations were not whipsawed by conflicting guidance.
What still has to mature?
Two gaps. The first is the registry's own real-time detection capability. Today, registry takedown still relies heavily on third-party detection, and the 7-minute-to-2.5-hour window in the September wave is the gap between "first responder detects" and "registry removes." Closing that gap requires the registry itself to run inline scanning at publish time, which is technically expensive at npm's scale but is being discussed publicly. The second is the consumer-side residual install window: even a 12-hour response is hours during which builds pull malicious code, and the only durable defense is the soak window plus --ignore-scripts discipline on the consumer side.
How Safeguard Helps
Safeguard's malicious-package feed pulls from the OpenSSF malicious-packages repository, npm registry quarantine signals, PyPI quarantine, and a curated set of commercial threat-intel feeds into a single stream that correlates against every lockfile in your tenant. When a Shai-Hulud-class wave hits, the dashboard surfaces affected products and the build history that resolved each tainted version within minutes. Postinstall-script audit identifies every install hook in your lockfile and lets policy enforce --ignore-scripts globally with per-package allow-lists for legitimate hooks. Soak-window policy gates can refuse installs of new versions of selected critical packages for a configurable cooling-off period, sized to your tolerance against the empirical registry response times. The provenance verification engine reads Sigstore attestations from npm to detect when a new version was published from an unexpected workflow file, catching maintainer-takeover patterns earlier in the chain. The result is that the next time a wave like Shai-Hulud breaks at 03:00 UTC, your on-call team has a definitive "are we affected?" answer before the first message hits Slack.