Axios NPM Supply Chain Attack (2026): What Happened and What to Do
On March 31, 2026, two malicious versions of the axios npm package were published using a compromised maintainer account. The affected versions, axios@1.14.1 and axios@0.30.4, introduced a hidden dependency that deployed a cross-platform remote access trojan. If you ran npm install between 00:21 and 03:15 UTC that day without a pinned lockfile, you need to check your environment now.
Axios has over 100 million weekly downloads and 174,000 dependent npm packages. Google Threat Intelligence Group subsequently attributed the attack to UNC1069, a financially motivated North Korea-nexus threat actor. This was not an opportunist who got lucky.
We have seen this playbook before. The actor behind it this time is different.
How to Check if You Were Affected
Run this against your lockfiles:
grep -E "axios@(1\.14\.1|0\.30\.4)|plain-crypto-js" package-lock.json yarn.lock 2>/dev/null
If anything comes back, treat that machine as compromised and work through the steps below.
If you were pinned to a clean version and did not run a fresh install between 00:21 and 03:15 UTC on March 31, you are not directly affected. The risk is wider than it looks for teams that do not pin versions directly: packages depending on axios without a pinned version would have resolved to 1.14.1 as the latest tag during the window. Wiz confirmed axios is present in approximately 80% of cloud and code environments and observed the malicious versions in roughly 3% of environments it scanned. Transitive exposure is harder to rule out than direct exposure. This incident is tracked as GHSA-fw8c-xr5c-95f9 and MAL-2026-2306.
What to Do Now
Check your installed versions. Open package-lock.json or yarn.lock and confirm which axios version is pinned. Check build logs for the relevant install window.
Downgrade immediately. Move to axios@1.14.0 for 1.x users or axios@0.30.3 for anyone still on the 0.x branch.
Delete node_modules/plain-crypto-js/ if it is present. The payload self-destructs after execution, so absence of the folder does not confirm a clean system. Check the persistence artefacts below as a more reliable signal.
Check network logs for C2 activity. The payload contacted sfrclak[.]com or 142.11.206.73 on port 8000. Connections to either during the March 31 window confirm execution regardless of what node_modules shows.
Rotate credentials on any exposed machine. API keys, service tokens, CI/CD secrets, SSH keys: anything present on a machine where the malicious package may have installed. The RAT had full interactive access to whatever was reachable at install time.
If this ran in a CI pipeline, rotate any secrets injected into that environment and review pipeline logs for outbound connections during the window. Ephemeral runners destroy themselves after each job, but any secrets injected during the compromised run should still be rotated.
Running npm audit fix will not help here. The advisory database was not updated during the exposure window, and the command only surfaces known vulnerabilities with published entries. A freshly poisoned version of a trusted package is exactly what it cannot see.
For a practical guide to dependency auditing and what a structured lockfile review looks like, see the npm vulnerability scanner guide.
What Happened in the Axios NPM Compromise
The attacker did not find a vulnerability in axios itself. There is zero malicious code inside the library. The compromise worked by hijacking the npm account of lead maintainer Jason Saayman through a targeted social engineering campaign that began approximately two weeks before the publish date, then using a pre-staged malicious dependency called plain-crypto-js@4.2.1 to deliver the payload.
Each poisoned release pulled in plain-crypto-js@4.2.1 as a runtime dependency. The package masquerades as the legitimate crypto-js library. It contains 56 source files copied verbatim from the real thing, with two additions: a postinstall hook in package.json and an obfuscated dropper script named setup.js.
The malicious versions were live for approximately three hours before npm removed them.
How the Axios NPM Attack Was Staged
This was not opportunistic. The staging started 18 hours before the compromised axios releases appeared.
The attacker published plain-crypto-js@4.2.0 on March 30 at 05:57 UTC, a clean decoy containing only legitimate crypto-js source code. Publishing a clean version first gave the nrwise@proton.me account a registry history. New accounts with no prior publishes trigger automated scanner heuristics, and the attacker knew it.
axios@1.14.1 appeared at 00:21 UTC on March 31. axios@0.30.4 followed 39 minutes later, targeting the legacy 0.x branch simultaneously to maximise coverage. Three separate payloads were pre-built for macOS, Windows, and Linux before a single malicious version hit the registry.
The social engineering followed a methodical playbook that Saayman documented in detail in his updated post mortem. The attacker cloned both a real company and its founder's identity, then reached out posing as that founder. Saayman was invited into a genuine Slack workspace built around the company's branding, with LinkedIn posts shared in channels, plausible team profiles, and what appeared to be accounts for other open source maintainers, designed to make the environment feel active and credible.
The campaign moved to a Microsoft Teams meeting staged to look like a group call. During it, Saayman was told something on his system was out of date and needed installing. He installed it, assuming it was a Teams requirement. That was the RAT. The entire sequence from initial outreach to payload delivery was built to feel like a routine professional interaction.
This maps directly to documented UNC1069 behaviour. Google's threat intelligence profile on the group describes the same operational pattern: a cloned identity, a virtual environment built to establish trust, and a fake software prompt as the final delivery step. It is the same playbook, tailored to an open source maintainer rather than a cryptocurrency target.
For a broader look at how npm supply chain attacks are typically structured, the Shai-Hulud analysis shows how this staging pattern has appeared before.
Why npm audit Found Nothing: The Self-Destructing Payload
The detail most likely to affect how you investigate this is the anti-forensics design.
After the RAT dropper executed, it deleted itself and swapped its own package.json for a clean stub. Malwarebytes confirmed that anyone who went looking through node_modules/plain-crypto-js/ after the fact would find a completely ordinary package manifest. No postinstall hook, no setup.js, nothing out of place. The attack had already cleaned up after itself.
StepSecurity, who detected the attack before any public disclosure, clocked the malware phoning home to the attacker's C2 within two seconds of npm install completing. The connection went out while the package manager was still working through the rest of the dependency tree. Running npm audit after the fact would not, and did not, catch it.
This is why the persistence artefacts are a more reliable indicator than node_modules. The RAT drops platform-specific files that survive after setup.js removes itself. Check for:
- macOS:
/Library/Caches/com.apple.act.mond - Windows:
%PROGRAMDATA%\wt.exe - Linux:
/tmp/ld.py
Finding any of these means the payload executed and the system is compromised regardless of what node_modules shows. Datadog Security Labs found that the Windows and Linux RAT payloads both had bugs that reduced their impact, and the Linux version crashes outright in containerised environments. The macOS payload ran cleanly. Worth knowing when you are scoping the incident, but none of it changes what you need to do.
The OIDC Provenance Gap That Should Have Been an Alert
There is a forensic signal in the npm registry metadata that would have caught this before install.
Every legitimate axios 1.x release is published via GitHub Actions using npm's OIDC trusted publishing, which ties each release to a specific, verifiable workflow run. axios@1.14.1 has none of that: published directly from the compromised account with no OIDC token, no corresponding GitHub commit, and no tag in the axios repository. The jasonsaayman account email in the registry metadata had also been changed to an attacker-controlled ProtonMail address.
As Saayman wrote in the post mortem: "Publishing directly from a personal account was a risk that could have been avoided. The OIDC flow and immutable release setup we are now adopting should have been in place before this happened."
You can verify provenance on any npm package via the registry API at https://registry.npmjs.org/<package>. Look at the _npmUser field for each version. Legitimate axios releases carry a trustedPublisher block that links back to the exact GitHub Actions workflow that ran the publish. On 1.14.1, that field is gone. No trusted publisher, no gitHead, no repository tag. When a package with an established automated release process suddenly ships a version with none of those markers, that is the signal. It was sitting in the registry metadata before anyone ran npm install.
Socket, StepSecurity, and similar supply chain monitoring tools will surface this automatically. If you are not running any of them, checking for a matching GitHub tag before installing a new version of a critical dependency is a manual step that takes thirty seconds.
Who Was Behind the Axios NPM Attack
Google Threat Intelligence Group attributed the attack to UNC1069, a financially motivated North Korea-nexus threat actor active since at least 2018. Microsoft independently attributed the same infrastructure to Sapphire Sleet, a different label for the same or closely related cluster. The second-stage RAT was identified by Google as WAVESHAPER.V2, an updated version of a backdoor previously associated with UNC1069 operations.
Google's assessment was that the incident could have far-reaching impacts given the package's scale, and noted it is separate from the TeamPCP campaign that targeted Trivy, LiteLLM, and Checkmarx earlier in March 2026. Two significant npm supply chain attacks within weeks of each other, by different threat actors. The registry is being treated as an attack surface, not an afterthought.
The axios attack also did not stay contained to the axios package. Socket identified two additional packages distributing the same plain-crypto-js payload: @shadanai/openclaw and @qqbrowser/openclaw-qbot. The openclaw connection is notable. This is the same package family covered in the OpenClaw security analysis on this blog. The payload spread beyond the headline incident.
The containment response was faster than it could have been because of two things. DigitalBrainJS, an axios collaborator who had less permission than the compromised account, still managed to open a deprecation PR and escalate directly to npm at 01:38 UTC. And Saayman published a detailed post mortem including a timeline, specific IOCs, and a self-critique of the publishing workflow gaps that made the attack possible. That level of disclosure is not standard after an incident of this kind, and it gave defenders materially better data than they would otherwise have had.
As Saayman wrote: "Open source maintainers with high-impact packages are active targets for sophisticated social engineering. Hyper vigilance is needed both on the registry and in a personal capacity."
The planning for this attack started two weeks before a single malicious package appeared on npm. The presence on the registry lasted three hours. A state-sponsored team invested a fortnight of preparation to exploit a three-hour window, because the package on the other side of that window installs automatically in 80% of cloud environments.
That is what makes axios a high-value target. Not the code. The trust. A package that reaches this many pipelines and developer machines without a second look is worth the preparation cost many times over. The registry window is short because it has to be. The damage is done before anyone raises the alarm.
For context on how the supply chain risk picture has been developing, the Gartner Supply Chain Retrospective covers the longer trend line. For a technical breakdown of how npm supply chain attacks work at the audit level, see Auditing the npm Supply Chain.
Get practical security insights delivered to your inbox.
Snyk advisory: SNYK-JS-AXIOS-15850650. GitHub advisory: GHSA-fw8c-xr5c-95f9. Malware tracking: MAL-2026-2306. CWE-506 (Embedded Malicious Code). CVSS 9.3 critical. No CVE assigned. Detection: StepSecurity (Ashish Kurmi). Forensic analysis: Datadog Security Labs. Attribution: Google Threat Intelligence Group (UNC1069), Microsoft Threat Intelligence (Sapphire Sleet).
Member discussion