Axios Supply Chain Attack: March 2026 Post-Mortem
On March 30–31, 2026, axios was compromised. Stolen npm token. Malicious versions 1.14.1 and 0.30.4 published. Cross-platform RAT delivered to every project that updated. npm audit showed 0 vulnerabilities before, during, and after. This is the post-mortem.
Attack Confirmed: March 30–31, 2026
axios was compromised. Malicious versions [email protected] and [email protected] were published via a stolen npm token for maintainer jasonsaayman. Both versions dropped a cross-platform Remote Access Trojan. npm audit returned zero vulnerabilities for both versions. This page was originally written as a structural threat model. The attack occurred before publication.
Confirmed Attack Profile
jasonsaayman Malicious versions:[email protected], [email protected] Payload:Cross-platform Remote Access Trojan (RAT) Pre-stage:Attacker published [email protected] 18 hours before the attack to avoid zero-history alarms npm audit warnings:Zero: before, during, and after Detection:StepSecurity's AI Package Analyst detected outbound C2 connection at 1.1 seconds into install What Actually Happened
The attacker obtained a long-lived npm access token for jasonsaayman, axios's sole maintainer. Not an OIDC token (those are ephemeral and scoped to GitHub Actions workflows), just a classic long-lived credential. The attacker changed the registered email on the account to [email protected].
At 00:21 UTC on March 31, [email protected] was published. An hour later, [email protected] followed, poisoning both the stable and legacy release branches simultaneously. The forensic tell: legitimate axios releases include "_npmUser": {"email": "[email protected]", "trustedPublisher": {...}}. The malicious versions showed "email": "[email protected]" with no gitHead or OIDC binding. Neither version exists in the GitHub repo: no tags, no commits, no release branches.
The pre-staging was deliberate. The attack dependency, [email protected], designed to look like a legitimate crypto-js alternative, was published 18 hours before the axios releases specifically to avoid "zero-history package" detection heuristics.
The Structural Gap: Not a Code Vulnerability
This is what makes axios a different class of risk. There is no vulnerable code in axios. No buffer overflow, no SQL injection, no dependency with a known CVE. The package is healthy by every quality metric:
- 11.6 years of consistent maintenance
- Active release cadence (35+ major versions)
- Growing download trend (101M weekly)
- Healthy GitHub activity
The vulnerability was structural: one person controlled publish access for a package that 101 million weekly installs depended on. One token was the only barrier between clean software and backdoored software entering every JavaScript project that uses axios.
Why Existing Tools Would Miss It
- npm audit: Scans for known CVEs. There are none. A credential compromise attack uses no known vulnerability in axios itself.
- Snyk / Socket.dev: Dependency vulnerability scanners look for known malicious patterns or CVEs. A newly published version with fresh malicious code has no prior signature to match.
- SBOMs (Software Bill of Materials): Inventories what you have. Does not measure who controls what you have, or what happens if that person's token is stolen.
- Code audits: You cannot audit a package that hasn't been published yet. The malicious code doesn't exist until the attacker publishes it.
- OIDC/Provenance: Even packages with CI/CD provenance configured have human maintainers with long-lived personal tokens as bypass paths. A human maintainer's personal access token is always an exception path to OIDC controls.
None of these tools measure the structural fragility that made this attack possible: a single person's credential concentration relative to the blast radius of their package.
The Structural Signals Right Now
Here is what npx proof-of-commitment axios returns today:
| Package | Score | Risk | Maintainers | Downloads/wk | Age |
|---|---|---|---|---|---|
| axios | 86 | 🔴 CRITICAL | 1 | 82M | 11.6 yrs |
The score breakdown: longevity=25 momentum=22 releases=20 maintainers=4 github=15
Score 86 is nearly perfect. Axios is, by behavioral metrics, an exceptionally well-maintained package. The CRITICAL flag fires despite this, because the behavioral score measures quality and quality is orthogonal to structural risk. A well-maintained package with 82M weekly downloads and one maintainer is not safer than a poorly-maintained package with the same profile. It's a higher-value target.
Why the CRITICAL Flag Exists
The CRITICAL threshold is: sole maintainer + >10M weekly downloads.
This threshold is deliberately aggressive. At 10 million weekly installs, compromising a single person's publish credential has enough blast radius to be worth a nation-state level attack. The ua-parser-js attack (2021) demonstrated exactly this: 7M weekly downloads, one token, nation-state level response required.
Axios has been in the CRITICAL zone throughout its history. Anyone running the audit today sees the same flag. Anyone who runs it tomorrow will see the same flag, unless the governance changes.
The Specific Structural Gap: Long-Lived Tokens vs. OIDC
This attack vector doesn't require a zero-day. It requires a token management failure: specifically, the existence of a long-lived npm access token that is not rotated or expired.
The npm ecosystem has increasingly adopted OIDC-based provenance, where packages published through CI/CD pipelines can include cryptographic proof of origin. When this works, it creates a verifiable chain: code commit → CI pipeline → npm publish → provenance attestation.
Long-lived personal access tokens are the bypass. They exist outside OIDC. They don't expire by default. They aren't tied to a specific pipeline or commit. They represent a maintainer saying "I want to be able to publish from anywhere, at any time, without going through CI." That's a reasonable developer ergonomics preference. It's also, for a 101M-download package, a catastrophic governance gap.
The structural question proof-of-commitment surfaces is not "does this package have provenance?" It's: how many people can publish this package, and what's the blast radius if any one of those credentials is stolen? For axios: one person controls publish for 82 million weekly downloads.
What Would Change the Structural Risk
The structural interventions that would materially reduce risk are not code audits, SBOMs, or Snyk scans:
- Requiring OIDC for all publishes: Disabling personal access token publishing for packages above a download threshold. npm has the mechanism; it's not enforced.
- Multi-maintainer governance: Any package with >10M weekly downloads requiring at least two publishers to sign a release. Industry convention doesn't enforce this.
- Token rotation policy: Long-lived tokens expiring automatically after 90 days. npm supports this; most maintainers don't use it.
- Monitoring for single-maintainer critical packages: Your security team running
npx proof-of-commitment --file package.jsontoday will flag axios for review.
The last one is the one you can act on today.
The Broader Pattern
axios is not unusual. It's the expected result of a structural condition that exists throughout the npm ecosystem. Packages with massive blast radius maintained by a single person, secured by a single credential.
We analyzed the top 50 npm packages by downloads and found that a significant fraction share the same structural profile as axios: sole maintainer, critical download volume, no secondary publish controls. The attack surface isn't one package. It's a category of packages that have organically grown far beyond what their governance model was designed to support.
npm audit will tell you when a CVE is filed against one of these packages. That's after the attack. The behavioral signal (sole maintainer, massive downloads, token concentration) exists before the attack, permanently, until the governance changes.
Check Your Dependencies
Run your own package.json through proof-of-commitment in under 10 seconds:
# Check a specific package
npx proof-of-commitment axios
# Check your whole project
npx proof-of-commitment --file package.json The output will flag packages in the same structural risk category as axios. CRITICAL means: if this maintainer's credential is compromised, your users receive the payload.
Web interface: getcommit.dev/audit
GitHub Action (runs on every PR, comments with risk scores):
- uses: piiiico/proof-of-commitment@main
with:
fail-on-critical: false
comment-on-pr: true MCP server for Claude Desktop, Cursor, or Windsurf to check packages while you code:
{
"mcpServers": {
"proof-of-commitment": {
"type": "streamable-http",
"url": "https://poc-backend.amdal-dev.workers.dev/mcp"
}
}
} We're building Commit: trust infrastructure for the autonomous economy. Behavioral commitment data, not declarations.
Related: Three npm Disasters That Were Predictable · State of npm Trust: April 2026 · The Thesis