Axios was the first npm package I ever installed.
I was at Code Fellows in Seattle, learning Node.js for the first time, and the instructor walked us through making HTTP requests. npm install axios. That was it. One command, and suddenly I could talk to APIs. It felt like magic. I didn't think about where that package came from, who maintained it, or what happened between me hitting Enter and the code landing on my machine. None of us did. That trust was invisible, and it was total.
Yesterday, someone weaponized it.
What Happened
On March 30, an attacker created an npm account under the name nrwise and published a clean decoy package called plain-crypto-js@4.2.0. Eighteen hours later, they pushed a malicious update to version 4.2.1 containing a cross-platform RAT dropper. Then they compromised the npm account of Axios lead maintainer jasonsaayman, changed the account email to an attacker-controlled ProtonMail address, and published two malicious Axios versions: 1.14.1 and 0.30.4.
The only modification to Axios was adding plain-crypto-js as a dependency. No source files were changed. The malicious package existed solely to execute a postinstall script that deployed platform-specific RATs: a compiled binary for macOS disguised as an Apple daemon, a PowerShell payload for Windows, and a Python script for Linux. The C2 callback happened within two seconds of npm install.
Socket's automated scanner flagged the malicious package within six minutes. npm removed both versions roughly two hours later. But Axios has approximately 100 million weekly downloads. Even a two-hour window at that scale is devastating.
The Architectural Flaw Nobody Wants to Name
Here's the part that should keep every engineering leader awake: the maintainer says he had MFA enabled. "I have 2fa / mfa on practically everything," he wrote in the GitHub issue tracking the incident.
It didn't matter.
npm supports "automation tokens" and "classic tokens" that bypass multi-factor authentication entirely. By design. These tokens exist so CI/CD systems can publish packages without human interaction. They're long-lived, they're bearer tokens, and if one is stolen, the attacker has full publish access to every package on that account.
This isn't an implementation gap. It's an architectural decision. npm built a system where MFA is optional at the most critical moment: the moment code ships to millions of machines. The maintainer did everything right. Enabled 2FA. Used GitHub Actions with OIDC trusted publishing for legitimate releases. But a single long-lived token, likely sitting in an environment variable or CI configuration somewhere, made all of that irrelevant.
The Axios attack is the third major npm supply chain incident in seven months. In August 2025, the Nx monorepo package was trojanized, harvesting 2,349 credentials from over 1,000 developer machines. In September, an attacker compromised 18 packages with 2.6 billion combined weekly downloads, including Chalk and Debug, through maintainer phishing. In 2025, over 99% of all open source malware targeted npm specifically.
The pattern is consistent: steal a token, publish a version, let the ecosystem's trust model do the rest. npm published a hardening update in February 2026, but the fundamental architecture of long-lived, MFA-bypassing tokens remains in place.
The Blast Radius You're Not Thinking About
Most coverage of the Axios attack focuses on developer workstations. That's the wrong lens.
Think about where npm install actually runs. It runs in CI/CD pipelines. Those pipelines have access to deployment secrets, cloud credentials, database connection strings, and production infrastructure tokens. StepSecurity's Harden-Runner product detected the RAT's C2 callback in the Backstage repository's CI pipeline during the attack window. That's a real-world detection of a supply chain attack executing inside enterprise CI.
The RAT lacked persistence mechanisms, which suggests smash-and-grab credential exfiltration rather than long-term access. This makes the CI/CD angle even more concerning. An attacker who executes code inside a CI pipeline for even two seconds can read every environment variable in that runner. AWS keys. Database credentials. API tokens for production services. The blast radius isn't "a developer's laptop was compromised." It's "every CI system that ran npm install during those two hours may have leaked its secrets."
This connects directly to a pattern I've written about before: the uncomfortable assumptions organizations make about CI/CD trust models. We treat build pipelines as trusted environments, but they're executing arbitrary code from external registries on every build. The Axios attack didn't exploit a novel vulnerability. It exploited the normal, expected behavior of how npm packages are installed.
The Ghost in Your node_modules
The most sophisticated element of this attack wasn't the RAT itself. It was the cleanup.
After execution, the dropper deleted itself, deleted the malicious package.json, and renamed a clean backup file to take its place. The result: plain-crypto-js in your node_modules now reports version 4.2.0 (the clean decoy), not 4.2.1 (the malicious version). Running npm list or npm audit after the attack window shows clean results, even if the RAT binary is still running on your system.
This is a direct challenge to every software composition analysis tool in the market. If the malicious package self-destructs and restores a clean version, your SCA scanner reports a clean bill of health while a RAT beacons to a C2 server every 60 seconds. Incident response teams can't rely on npm list or lockfile inspection alone. They need to check for the actual RAT artifacts: /Library/Caches/com.apple.act.mond on macOS, %PROGRAMDATA%\wt.exe on Windows, /tmp/ld.py on Linux.
Vercel responded by proactively blocking the C2 domain at the build infrastructure level and advising teams to rotate all credentials. That's the right posture: assume compromise, rotate everything, verify from artifacts rather than package metadata.
The Trust Model That Needs to Change
The Axios attack worked because npm's security model places catastrophic blast radius behind a single credential. One stolen token can push code to 100 million machines. MFA doesn't help because the token system was designed to bypass it. The tooling caught this one fast, six minutes from publication to detection, but detection isn't prevention.
What needs to change isn't just npm's token model (though deprecating long-lived tokens in favor of OIDC trusted publishing would be a start). It's the postinstall script model that lets any dependency execute arbitrary code during installation, a pattern we've seen exploited across multiple protocols now. It's the implicit trust that npm install is safe because the package name is familiar, the same invisible attack surface created by every third-party dependency in your stack. It's the assumption that your lockfile protects you (it does, but only if it was committed before the malicious version was published and your install didn't update it).
The broader pattern is unmistakable. npm supply chain attacks aren't edge cases anymore. They're industrial-scale operations targeting the most popular packages in the ecosystem. The defenses that caught Axios in two hours didn't exist three years ago. But the architecture that made the attack possible hasn't changed either.
What to Do Right Now
If you run JavaScript in production, here's the immediate checklist:
- Check your lockfiles. Search for
plain-crypto-js in your package-lock.json or yarn.lock. If it's there, assume compromise.
- Check for RAT artifacts. Don't trust
npm list. Look for the actual binaries: com.apple.act.mond (macOS), wt.exe (Windows), ld.py (Linux).
- Rotate credentials. If any CI/CD pipeline ran
npm install between 00:21 and 03:15 UTC on March 31, rotate every secret that pipeline had access to.
- Pin your dependencies. Use exact versions, not ranges. Commit your lockfile. Run
npm ci instead of npm install in CI.
- Run
npm ci --ignore-scripts in CI/CD. This prevents postinstall hooks from executing. Yes, some packages will break. That's a feature, not a bug; it forces you to explicitly whitelist packages that need install scripts.
- Audit your npm tokens. Delete every classic and automation token you're not actively using. Move to OIDC trusted publishing where possible.
The first dependency I ever installed just deployed a RAT to millions of machines. The tools caught it. The architecture that made it possible is still running. That's the problem worth solving.