Skip to content

What Happened in the Axios npm Supply Chain Attack? (March 2026 Incident Explained)

Problem

When I ran npm install on a project yesterday, I noticed something strange in my package.json diff:

package.json-diff
"axios": "^1.14.0"
"axios": "^1.14.1"

I hadn’t updated axios. My AI coding assistant suggested running npm install, and I almost did without checking. But then I saw this Reddit post:

reddit-alert.txt
"A supply chain attack hit axios a few hours ago. Version 1.14.1 silently
pulls in [email protected], which is an obfuscated RAT dropper."

That was close. Let me explain what happened and how to protect yourself.

What Happened?

On March 30, 2026, attackers compromised the npm account of axios core maintainer “jasonsaayman” and published two malicious versions:

The attack was sophisticated. Here’s what the attackers did:

1. Account Hijacking

They changed the maintainer’s email to an anonymous ProtonMail address and bypassed GitHub Actions workflows entirely, publishing directly via npm CLI.

2. Hidden Dependency Injection

The attackers didn’t modify axios source code. Instead, they injected a hidden dependency that was never used in the actual axios code:

dependency-tree.txt
└── [email protected] (MALICIOUS - never referenced in code)
└── setup.js (postinstall script → RAT dropper)

3. Pre-Meditated Timing

They published [email protected] (clean) 18 hours before [email protected] (malicious). This avoided security tools that flag brand new suspicious packages.

The Malware: Cross-Platform RAT Dropper

When developers ran npm install axios, the malicious package executed platform-specific payloads:

attack-flow.txt
┌─────────────────────────────────────────────────────────────┐
│ npm install axios │
└─────────────────────┬───────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
[email protected] package.json includes [email protected]
└─────────────────────┬───────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ postinstall hook triggers setup.js │
└─────────────────────┬───────────────────────────────────────┘
┌─────────┴─────────┐
│ Platform Detection │
└─────────┬─────────┘
┌────────────┼────────────┐
▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐
│ macOS │ │ Windows │ │ Linux │
└────┬────┘ └────┬────┘ └────┬────┘
▼ ▼ ▼
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│/Library/Caches│ │%PROGRAMDATA% │ │ /tmp/ld.py │
│com.apple.act. │ │ \wt.exe │ │ │
│ mond │ │ │ │ │
└──────────────┘ └──────────────┘ └──────────────┘
│ │ │
└────────────┼────────────┘
┌─────────────────────┐
│ C2 Server Connection │
└─────────────────────┘
┌─────────────────────┐
│ Self-Cleaning │
│ (deletes evidence) │
└─────────────────────┘

Platform-Specific Behavior

macOS:

macOS-malware-location.sh
# Malware location
/Library/Caches/com.apple.act.mond

Windows:

windows-malware-location.ps1
# PowerShell RAT locations
$env:PROGRAMDATA\wt.exe
$env:TEMP\6202033.ps1

Linux:

linux-malware-location.sh
# Python RAT dropper
/tmp/ld.py

Self-Cleaning Mechanism

After execution, the malware deletes setup.js and replaces package.json with a clean version. This means even checking node_modules afterward shows clean files.

Timeline of Events

attack-timeline.txt
T-18 hours: [email protected] published (clean, cover package)
T-0: [email protected] published (malicious)
T+hours: Security researchers detect attack
T+same day: npm unpublishes malicious versions

How to Check If You Were Affected

I immediately checked my systems:

check-infection.sh
# Check for the malicious package
find node_modules -name "plain-crypto-js" -type d
# macOS indicators
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null
# Windows (PowerShell)
dir $env:PROGRAMDATA\wt.exe 2>$null
dir $env:TEMP\6202033.ps1 2>$null
# Linux
ls /tmp/ld.py 2>/dev/null

If you find plain-crypto-js in your node_modules, even if the package.json looks clean now, that’s a high-risk indicator. The self-cleaning mechanism only hides the evidence after execution.

How to Protect Your Projects

1. Use npm ci Instead of npm install

npm-comparison.sh
# Wrong: npm install can upgrade versions unexpectedly
npm install
# Right: npm ci strictly follows package-lock.json
npm ci

npm ci ignores package.json and installs exactly what’s in package-lock.json. This prevents auto-upgrading to malicious versions.

2. Disable npm Scripts

I now run installs with scripts disabled:

safe-install.sh
npm ci --ignore-scripts

Or set it globally in .npmrc:

.npmrc
ignore-scripts=true
audit=true
strict-peer-dependencies=true

3. Pin Exact Versions

package.json-example.js
// Wrong: Allows upgrades to any 1.x.x version
"axios": "^1.14.0"
// Right: Exact version, no surprises
"axios": "1.14.0"

4. Add Dependency Auditing to CI/CD

.github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci --ignore-scripts
- run: npm audit --audit-level=high

5. Check package.json Diffs Before Installing

This is critical when using AI coding tools. I’ve caught several suspicious suggestions by always reviewing diffs:

check-diff.sh
# Always check what changed
git diff package.json
# Check for unexpected dependencies
git diff package-lock.json

The Reason This Attack Worked

The attack exploited several weaknesses in npm’s trust model:

  1. Maintainer account trust: npm trusts packages from verified maintainer accounts. When an account is compromised, all packages from that maintainer appear legitimate.

  2. Automatic version upgrades: Using ^1.14.0 allows npm to install 1.14.1 automatically, pulling in the malicious version.

  3. postinstall scripts: npm runs scripts automatically during installation, giving packages execute-by-default power.

  4. AI coding tools target: Attackers specifically targeted developers who run npm install suggestions from AI tools without checking diffs.

What I’m Doing Differently

After this incident, I made these changes to my workflow:

  1. Never run npm install blindly from AI suggestions - I always check the package.json diff first.

  2. Use npm ci --ignore-scripts for all projects - This prevents automatic script execution.

  3. Pin all dependency versions - No more ^ or ~ in my package.json files.

  4. Add security scanning to CI - Every pull request now runs npm audit.

  5. Subscribe to security advisories - I enabled npm security notifications.

Summary

In this post, I explained the March 2026 axios npm supply chain attack. Attackers hijacked a maintainer account and injected a cross-platform RAT dropper through a hidden dependency. The key takeaways are:

  • Use npm ci instead of npm install to strictly follow lockfiles
  • Run npm ci --ignore-scripts to prevent automatic script execution
  • Pin exact versions in package.json
  • Always check package.json diffs before installing, especially with AI tools
  • Add npm audit to your CI/CD pipeline

This attack was a wake-up call. The convenience of AI coding assistants and automatic dependency management must be balanced with security diligence. If I hadn’t checked that package.json diff, I would have installed a RAT on my system.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments