What happened
Around 04:00 UTC on May 24, 2026, an attacker who had obtained a long-lived classic npm access token belonging to one of Axios's lead maintainers published two malicious versions of the package: 1.14.1 on the current branch and 0.30.4 on the legacy branch, 39 minutes apart. Anyone with a caret range like ^1.14.0 in their lockfile pulled the bad version on the next npm install. Because npm install runs automatically in most CI/CD pipelines, this happened to many organizations without anyone touching a keyboard.
The attacker was disciplined. They did not modify any of Axios's 86 source files. They did not touch the build pipeline. They added one line to package.json - a new dependency on a package called plain-crypto.js. That dependency was never imported by any Axios source file. It had no API surface consumed by anything in the package. It existed for a single purpose: its postinstall script.
When a downstream user ran npm install, npm fetched plain-crypto.js, executed its postinstall, and the rest happened in about a second. The postinstall dropped a setup.js with two layers of obfuscation. setup.js detected the operating system, contacted a command-and-control server, downloaded the platform-specific RAT payload, executed it, and then deleted itself - renaming a pre-staged clean package.md back to package.json. The forensic trail evaporated. The user never saw a prompt, an error, or anything unusual in npm install output. They were compromised in 1.1 seconds.
Socket.dev found the attack first and disclosed it. The maintainer account was locked. npm pulled the bad versions. The C2 IP was taken offline within hours. But thousands of CI runs had already executed the dropper before any of that happened.
How SCG scores it
Our Supply Chain Guard specification defines a divergence-signal taxonomy that scores each released version of a package against its own history. Each signal has a weight; the sum maps to allow / require_approval / deny. The taxonomy is the result of months of analysis across real incidents - Mini Shai-Hulud in May, AccessPress in 2021, the Display Widgets backdoor, and now Axios. Every incident we've studied has contributed signals to the model.
Run against Axios 1.14.1, the signals fire as follows:
A composite score of 340 against a deny threshold of 80 is not a close call. The registry mirror - the free SCG surface that any organization can adopt by changing one line in their npm config - refuses to serve the install. CI runs configured against the mirror fail cleanly with a structured error pointing at the divergence trace. The user sees a clear refusal with a complete audit record of why.
The signals worth highlighting
Most of the trace above is conventional. New packaging behavior, new outbound network targets, missing build attestation - these are the staple signals any supply-chain scanner looks for. The three that matter most for Axios-class attacks, because they target the specific cleverness of this attacker:
Static analysis pass: walk every .js/.ts/.mjs file in the package, collect every import and require, compare against the dependencies declared in package.json. Any dep that's declared but never imported is suspicious. There is almost no legitimate reason for this pattern. This is the fingerprint of the Axios attack- the attacker's entire technique relied on a smuggler dep that nothing imported.
A dependency whose entire functional value is its postinstall hook - no exports actually consumed by the parent - is a smuggling mechanism. Pairs with the above to flag the plain-crypto.js-shaped attacker pattern with high confidence.
Postinstall scripts that write or rename files inside their own package directory after running. The Axios dropper deleted setup.js and swapped package.json with a pre-staged clean version to erase forensic evidence. Legitimate postinstalls don't rewrite themselves. This signal is one of the few that single-handedly justifies a deny verdict regardless of the rest of the score.
The full taxonomy - sixty-some signals across npm, PyPI, WordPress, and the agent ecosystems - is documented in the SCG specification. We publish weights and decision thresholds because they should be adversarially auditable. If you find a signal you think we're weighting wrong, the issues are open.
The fundamental fix: HITL on every publish
Even with perfect divergence detection on the install side, the attacker still gets to publish the bad version. Downstream defense limits blast radius; it doesn't prevent the attack at its source. The fix at the source is human-in-the-loop on every publish.
If Axios's maintainer had been publishing through a tool that required out-of-band confirmation - a push notification to a second device, an SMS reply, a hardware key tap - the attacker with the stolen token alone could not have shipped. The HITL would have fired on the publish attempt. The maintainer's phone would have shown “publish axios@1.14.1?” - and the attacker would have needed to also compromise that channel. That's the kind of compound attack cost that defeats opportunistic credential theft.
We had this feature scoped as a paid premium tier called Verified Publisher. After watching what happened to Axios, that pricing is wrong. Packages with massive blast radius - the load-bearing OSS commons that runs the internet - can't be on a paid SKU. Effective immediately, our spec changes: Verified Publisher will be free for any package above 100,000 weekly downloads. We'll monetize the long tail and enterprise plugins, not the load-bearing OSS dependencies that we all rely on.
The standalone tool: synoi-scg inspect
One of the lessons of this attack is that detection has to be available to everyone, not just to organizations that have adopted a full supply-chain governance platform. We're committing to ship a standalone CLI:
No signup, no infrastructure, no opt-in from the package author. The tool pulls the package straight from the public npm registry, walks its source tree, computes the divergence signals, and gives a verdict. It works on Axios. It works on any package. It works on your cousin's side project that has fourteen weekly downloads.
Distribution shape: npx @synoi/scg-inspect <pkg> on the command line, plus an extension into Cursor / VS Code that shows the divergence score next to every package suggestion the agent makes. Free, public, ungated.
What to do today, if you might be affected
Run this first to see if Axios is anywhere in your tree:
If you see 1.14.1 or 0.30.4, treat the machine as compromised. Don't just delete files. Rotate every API key, every credential, every token that was reachable from that environment. Audit your shell history, your ~/.aws/credentials, your keychain, your CI secrets. If the affected machine is a build server, audit every artifact it built since the install date.
If you're clean, this is the moment to lock the door. Pin your lockfile to exact versions. Subscribe to a supply-chain advisory feed that'll notify you when packages in your tree are flagged. Move maintainer accounts off long-lived classic tokens to granular automation tokens. Audit your dependency tree for packages you didn't know you had - the average npm project trusts 200 to 2,100 strangers with code execution. Today is a good day to start cutting that number down.
What we're doing about it
The six new signals land in the SCG taxonomy this week. The Verified Publisher free tier policy is now in the spec. The standalone synoi-scg inspectCLI is scoped and tracked. Sub-second blast-radius lookup against the receipt corpus is bumped in priority. We'll publish the divergence test suite that scores Axios so anyone - Socket, Snyk, OSV, individual researchers - can validate the scoring against their own data.
One thing to be honest about: SCG isn't in production yet. What you're reading is the spec, the divergence model that scores the spec, and the test suite that scores Axios at 340 - not a deployed product that caught this in the wild. The point of writing this post the same day as the disclosure isn't to take credit. It's to show that the answer to attacks like Axios isn't mysterious. It's a defensive layer that scores releases against their own history at install time, with an HITL gate on the publish side and a receipt-anchored blast-radius lookup for incident response. That defensive layer is what we're building. If you want to follow along, everything is in the open.
If you want to follow along, the spec lives in the Supply Chain Guard spec and the work items are tracked under conductor #205 (SCG Ecosystem Expansion umbrella). The new signals from this incident are conductor #212. We'll mark every commit that lands one of the six new signals so the trace is auditable.
Credit
Socket.dev disclosed the attack first and traced the dropper. Their writeup is the source of much of the technical detail above. We share the goal - make this class of attack harder and more expensive to execute - and we differ on architecture in places worth talking about over a beer at the next conference. The supply-chain security community is small enough that we all owe each other public credit when we're standing on each other's work.
If you're a maintainer of a package above 100,000 weekly downloads and you'd like early access to the Verified Publisher beta, reach out at supplychain@synoi.systems. Free, no contract, no upsell. We want to make sure the load-bearing OSS commons has a defense in depth that doesn't depend on anyone's billing department signing off.