← Back to Blog
· 6 min read · API Stronghold Team

NPM Supply Chain Attack: Why Expiring Tokens Beat Rotation

Cover image for NPM Supply Chain Attack: Why Expiring Tokens Beat Rotation

Axios maintainers woke up to bad news. Someone published malicious versions of the package. The attacker used a stolen token from a maintainer. This let them push code that steals data from apps using axios.

The attack started when the token leaked. NPM tokens do not expire by default. They last forever until revoked. The maintainer had it in a repo or CI config. Attackers found it and acted fast.

What did the malware do? It grabbed environment variables. Sent them to a server. It also scraped crypto wallets if present. Node apps got hit first, but browsers too since axios works in both environments.

Downloads spiked. Over 5,000 installs in hours. NPM yanked the versions. But the damage was done. Teams had to audit, roll back deploys, and check for leaks.

This is the problem with static tokens. They have full power and no time limit. One leak equals full access until someone notices.

The Attack Timeline

March 28, 2026. Malicious axios@1.7.1 appeared on the registry.

Users started reporting odd network calls from apps that hadn’t changed. GitHub issues flooded in. Maintainers traced it back to a compromised publish token, one that had been sitting in a CI config for years. They revoked it, yanked the malicious package versions, and published a post-mortem.

The window between publishing and takedown was several hours. In that time, 5,000+ installs ran the malicious payload. Each one sent environment variables to an attacker-controlled server. Crypto wallet files got scooped if present.

The maintainers did everything right after discovery. But “after discovery” is already too late when tokens have no expiration.

Root Cause: The Forever Token

The token that enabled this attack was not short-lived. It was a permanent NPM automation token, copied into a CI pipeline, sitting in configuration for however long the project had been active.

NPM creates tokens with no expiration by default. Developers copy them into GitHub Actions secrets, .env files, CI/CD variables, and sometimes accidentally into repositories. The token that authenticated the malicious axios publish had probably been valid for months or years before the breach.

What makes this worse: rotation is the standard advice for this exact scenario. Rotate tokens regularly. But rotation assumes you catch the compromise in time. If a token leaks quietly and an attacker waits, your rotation schedule just tells them when they need to act before you do.

The Trivy action attack, which happened the same month, confirmed this pattern again. Rewritten tags, compromised maintainer credentials, secrets exfiltrated from CI environments that assumed their credentials were safe.

Blast Radius: Why This Hit So Hard

5,000 installs in a few hours sounds contained. It was not.

Axios has over 100 million weekly downloads. Any Node or React app that ran npm install in that window pulled the malicious version. The malware did not discriminate: it exfiltrated any environment variable it could find. AWS credentials, Stripe keys, database passwords, GitHub tokens, crypto wallet seeds.

For each affected environment, the blast radius depended on what credentials were available. A developer’s local machine might have had staging keys. A CI runner might have had production AWS access. There was no way to know which environments were clean without auditing all of them.

This is the structural failure. A single compromised publish token created unlimited blast radius across tens of thousands of environments. The token itself had minimal permissions to the registry. But it acted as a lever that moved an enormous amount of downstream risk.

Fixes for NPM Publishers

The immediate fix after this incident is key rotation and audit. But that is the floor, not the ceiling.

Use OIDC for GitHub Actions publishing. Modern GitHub Actions workflows can authenticate to NPM without storing a token at all:

# .github/workflows/publish.yml
permissions:
  id-token: write
  contents: read

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'
      - run: npm ci
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

With OIDC properly configured, the NODE_AUTH_TOKEN can be a short-lived token issued per workflow run rather than a static secret. No stored token means no stored token to leak.

Set token expiration for any token you do store. NPM now supports granular token settings including expiration. Any token you create for automation should have an explicit TTL. One week is reasonable for most CI cases.

Audit your existing tokens regularly. Run npm token list and remove anything you do not recognize or no longer actively use. Old tokens from contractors, deprecated pipelines, or former team members are common sources of credential sprawl.

AI Agents and CI Pipelines

The same problem applies anywhere an AI agent runs in CI. Agents that automate builds, test deploys, and package publishing need publish access. If they hold static NPM tokens, every compromise of the agent context carries the full weight of those credentials.

MCP servers present the same exposure. A tool server with long-lived NPM publish access becomes a high-value target: compromise the tool, get the token, publish anything to any package that maintainer owns.

The architectural answer is the same as for human CI: tokens that expire before they can be weaponized.

Static tokens are the attack surface. Expiring ones aren't.

API Stronghold issues scoped, short-lived credentials to CI pipelines and AI agents. A compromised job gets a token that expires in minutes, not a key valid for years.

No credit card required

What Actually Fixes This

Rotation helps. It reduces the standing lifetime of compromised credentials. But the Axios attack proves its limits: an attacker who finds a token and moves in hours beats a 90-day rotation schedule every time.

Expiration changes the math entirely. A token with a 15-minute TTL is worthless by the time most attackers can operationalize it. A session-scoped token that expires when the publish job completes gives an attacker zero window to reuse it.

For AI agents specifically, the phantom token pattern takes this further. The agent never holds the real NPM publish credential. A credential broker intercepts the publish request, verifies the agent’s authorization, issues a token scoped to that specific package and action, valid for the duration of the operation. The real token never touches the agent environment. If a prompt injection or supply chain attack compromises the agent mid-run, there is nothing useful to extract.

The Axios incident was not a sophisticated attack. It was patient exploitation of a credential that had no natural death. Change that assumption and the attack stops working.

Make your publish tokens expire before attackers can use them

Short-lived, scoped credentials for NPM, AWS, and any API your pipeline touches. Set up in under 10 minutes.

No credit card required

Keep your API keys out of agent context

One vault for all your credentials. Scoped tokens, runtime injection, instant revocation. Free for 14 days, no credit card required.

Start Free Trial → No credit card required

Get posts like this in your inbox

AI agent security, secrets management, and credential leaks. One email per week, no fluff.

Your CI pipeline has permanent keys sitting in env vars right now. Scoped, expiring tokens fix that in an afternoon.

One vault for all your API keys

Zero-knowledge encryption. One-click sync to Vercel, GitHub, and AWS. Set up in 5 minutes — no credit card required.