Axios—one of the most widely used JavaScript HTTP clients—was briefly backdoored on npm on March 31, 2026. For a roughly three-hour window, installing the affected releases could deliver a cross-platform remote access trojan (RAT) to developer machines and CI environments. Google’s Threat Intelligence Group (GTIG) attributed the campaign to the North Korea–linked actor UNC1069. Last updated: April 1, 2026 (added attribution details, IOCs, and deeper technical analysis) Axios is downloaded roughly 100M+ times per week, and it shows up in an estimated ~80% of cloud code environments. That means axios is likely somewhere in your dependency tree—even if you never ran And on March 31, 2026, axios was compromised on npm. A threat actor tied to North Korea (UNC1069) took over the npm maintainer account “It’s gone now, so we’re fine” is the wrong conclusion. The malware attempts to cover its tracks: after execution it deletes itself and swaps This article breaks down what happened, how to determine whether you were affected, and what to do right now. Start with a quick dependency check:Bottom line: is your project safe?
npm install axios yourself.jasonsaayman and published axios@1.14.1 (00:21 UTC) and axios@0.30.4 (01:00 UTC). In Japan (JST), that maps to roughly 9:21 a.m. to 12:29 p.m. on March 31—right in the middle of normal business hours. The malicious versions were removed within about three hours, but if your CI ran or you installed dependencies during that window, you must assume exposure.package.json for a clean decoy. That means post-incident checks like browsing node_modules or running npm audit may show nothing. Wiz reported that execution of the malicious versions was observed in roughly ~3% of impacted environments. You can’t know whether you’re in the other 97% until you verify.
npm ls plain-crypto-js --all 2>/dev/null && echo "⚠ Potentially impacted" || echo "✓ This dependency was not found"
What happened
Key points
- The attacker compromised a primary axios maintainer’s npm account (
jasonsaayman)—and likely access to related tooling. Multiple investigations suggest a long-lived “classic” npm access token may have been abused. - The account email address was changed to an attacker-controlled ProtonMail address (
ifstap@proton.me). - Instead of modifying axios source code, the attacker used a stealthier technique: they added a single new dependency to
package.json(plain-crypto-js@4.2.1) so the malware ran as part of installation. - A RAT was delivered via a postinstall hook, targeting Windows, macOS, and Linux.
- The compromised releases did not appear in GitHub’s official tags/releases. The attacker published directly to npm, bypassing normal CI/CD and provenance workflows (including SLSA-style provenance via OIDC).
Compromised versions
The compromised releases were axios@1.14.1 (latest) and axios@0.30.4 (legacy). Safe versions are 1.14.0 and 0.30.3 or earlier.
Advisory tracking IDs: GHSA-fw8c-xr5c-95f9, MAL-2026-2306
Attribution
Google’s Threat Intelligence Group (GTIG) attributed the attack to the North Korea–nexus, financially motivated actor UNC1069. UNC1069 has been tracked since 2018 and is known for targeting crypto-related businesses, software developers, and financial organizations. GTIG and other investigations point to technical overlap with variants of the WAVESHAPER backdoor (including a newer WAVESHAPER.V2) and infrastructure patterns consistent with prior UNC1069 activity. Researchers also noted naming overlap between an internal macOS project name (“macWebT”) and components seen in campaigns associated with the BlueNoroff cluster.
GTIG chief analyst John Hultquist noted that while the full scope was still unclear, the popularity of the compromised package suggests the impact could be broad.
Related malicious packages
Socket’s analysis found additional packages distributing the same malware chain downstream of the axios incident:
- @shadanai/openclaw (multiple versions): bundles the malicious
plain-crypto-jspayload directly - @qqbrowser/openclaw-qbot@0.0.130: ships a tampered
axios@1.14.1inside its ownnode_modules, then triggersplain-crypto-jsas a transitive dependency
When it happened: detailed timeline
| Date/time (UTC) | Event |
|---|---|
| 2026-03-27 19:01 | Legitimate axios@1.14.0 published via GitHub Actions OIDC |
| 2026-03-30 05:57 | Attacker publishes plain-crypto-js@4.2.0 (clean decoy) to build registry history |
| 2026-03-30 ~ | plain-crypto-js@4.2.1 (malicious) published as a staged setup to reduce “brand-new package” suspicion |
| 2026-03-31 00:21 | Compromised jasonsaayman account publishes axios@1.14.1 (latest) directly to npm → compromise window begins |
| 2026-03-31 01:00 | Publishes axios@0.30.4 (legacy), contaminating both the 1.x and 0.x lines |
| 2026-03-31 ~03:29 | Malicious versions removed from npm → compromise window ends |
The attacker prepared the operation well ahead of time: they published the malicious dependency before the axios releases so automated scanners were less likely to treat it as “brand new.” In Japan (JST = UTC+9), the compromise window corresponds to roughly March 31, 09:21–12:29. If you’re correlating build history, match timestamps in UTC to avoid timezone mistakes.
Technical breakdown
Attack chain
npm install → dependency resolution pulls plain-crypto-js@4.2.1 → a postinstall hook runs setup.js → the script detects the OS → downloads an OS-specific stage-2 payload from a C2 server (sfrclak[.]com:8000) → executes the RAT → deletes setup.js and replaces package.json with a clean decoy. Some analyses estimate end-to-end compromise in roughly ~15 seconds from install to execution.
Obfuscation
The dropper (setup.js) uses two layers of obfuscation to frustrate static analysis. First it replaces Base64 padding characters with underscores and reverses strings; then it decrypts content using an XOR scheme with the key string OrDeR_7077 and the constant 333.
OS-specific RAT behavior
| OS | Stage-2 payload | Persistence path | Notes |
|---|---|---|---|
| macOS | Native C++ (Mach-O) binary WAVESHAPER.V2 |
/Library/Caches/com.apple.act.mond (masquerades as an Apple daemon) |
Uses AppleScript to download/execute. Reported technical overlap with the “webT” module from RustBucket-style campaigns. |
| Windows | PowerShell RAT | %PROGRAMDATA%\wt.exe (copied PowerShell binary)Temporary: %TEMP%\6202033.vbs / .ps1 |
Can execute arbitrary DLLs in memory. Uses cscript to launch VBS. |
| Linux | Python RAT (/tmp/ld.py) |
/tmp/.<random> (dot-prefixed hidden file) |
No explicit persistence mechanism (often disappears after reboot). Uses nohup to detach from the parent process. |
All three variants share the same C2 protocol, command set, and a 60-second beacon interval. Common capabilities include remote shell execution, binary injection, directory listing, process enumeration, and host reconnaissance. Elastic noted a useful detection clue: all variants reportedly hard-code an IE8/Windows XP User-Agent string—highly unusual in modern environments.
Self-deletion and forensic evasion
After the RAT launches, the dropper deletes setup.js and replaces the original package.json with a pre-staged clean decoy (package.md). That means post-incident inspection of node_modules/plain-crypto-js/ can look “clean,” and npm audit may not flag anything. However, the presence of the plain-crypto-js directory itself is a strong indicator—legitimate axios does not depend on it.
IOCs (indicators of compromise)
Network indicators
| Type | Value | Notes |
|---|---|---|
| C2 domain | sfrclak[.]com |
Port 8000. Express.js server. GET returns 500; responds to POST only. |
| C2 IP address | 142.11.206.73 |
Reported overlap with infrastructure patterns seen in prior UNC1069 activity. |
| Beaconing | HTTP POST every 60 seconds | Body contains packages.npm.org/product{0,1,2} (0=macOS, 1=Windows, 2=Linux) |
| User-Agent | IE8/Windows XP string | Shared across all OS variants; should stand out in modern telemetry. |
Package indicators
| Package | SHA256 |
|---|---|
axios@1.14.1 |
5bb67e88846096f1f8d42a0f0350c9c46260591567612ff9af46f98d1b7571cd |
axios@0.30.4 |
59336a964f110c25c112bcc5adca7090296b54ab33fa95c0744b94f8a0d80c0f |
plain-crypto-js@4.2.1 |
Contains a malicious postinstall hook |
File system indicators
| OS | Paths to check |
|---|---|
| macOS | /Library/Caches/com.apple.act.mond |
| Linux | /tmp/ld.py, /tmp/.<random> (dot-prefixed hidden file) |
| Windows | %PROGRAMDATA%\wt, %TEMP%\6202033.vbs / 6202033.ps1 (may exist only while running) |
Process indicators
- macOS:
osascriptexecution from$TMPDIR - Windows:
cscriptrunning a.vbsfrom%TEMP% - Linux:
python3 /tmp/ld.pyrunning in the background
Account indicators
- Compromised npm account:
jasonsaayman(email changed to:ifstap@proton.me) - Malicious package publisher:
nrwise(email:nrwise@proton.me)
Impact scope
When you could be impacted
- You resolved dependencies during March 31, 2026 00:21–03:29 UTC (roughly 3 hours) via
npm install,npm ci,yarn,pnpm,bun, etc. - Even if axios isn’t a direct dependency, it can arrive as a transitive dependency through CLIs, SDKs, build tooling, and frameworks.
- A CI/CD job, Docker build, cache refresh, or lockfile update ran automatically during the window.
- Watch for developer tooling and IDE extensions. Some extensions may fetch packages from registries in ways that don’t strictly follow your lockfile, depending on how they’re implemented and configured.
- If you used caret ranges such as
^1.14.0or^0.30.0, your environment could have auto-upgraded to the malicious patch release.
How big was it?
- Axios: ~100M weekly downloads (often cited as ~400M monthly downloads)
- Wiz observed axios in ~80% of cloud code environments
- Despite the short window, execution of the malicious versions was observed in ~3% of affected environments
Common failure modes
| Pattern | What happens | What gets missed |
|---|---|---|
| Automated CI builds | Build artifacts/images include the malicious dependency chain | Fixing the lockfile doesn’t remove already-built, already-running images |
| Developer machines updating dependencies | A RAT lands on a workstation via postinstall scripts | The dropper self-deletes, so visual inspection of node_modules often misses it |
Semver ranges (^ / ~) |
Your environment follows a malicious patch release without a review step | “Auto-upgrade” behavior is exactly what supply chain attackers exploit |
| Caches / proxy registries | Malicious versions linger in local caches or artifact proxies (Artifactory, etc.) | Even after npm removes the package, a cached copy can re-infect builds |
| IDE extensions | Packages may be fetched during project load | Some tooling can behave differently from your CI’s lockfile-driven installs |
How to check whether you were affected
Start with your lockfiles
Begin with your repo’s package-lock.json, yarn.lock, or pnpm-lock.yaml. If the compromised versions are recorded there, treat that as strong evidence you were exposed at install/build time.
# Check lockfiles for known bad versions / suspicious dependency strings
# (Linux/macOS)
rg -n "axios@1\.14\.1|axios@0\.30\.4|plain-crypto-js" package-lock.json yarn.lock pnpm-lock.yaml || true
# Confirm via npm dependency tree
npm ls axios --all
npm ls plain-crypto-js --all
# Check for the plain-crypto-js directory (its presence is itself suspicious)
ls -la node_modules/plain-crypto-js/ 2>/dev/nullVerify with SHA256 hashes
# Check tarballs in the npm cache
find ~/.npm/_cacache -name "*.tgz" -exec sha256sum {} \; | \
grep -E "5bb67e88846096f1f8d42a0f0350c9c46260591567612ff9af46f98d1b7571cd|59336a964f110c25c112bcc5adca7090296b54ab33fa95c0744b94f8a0d80c0f"Correlate CI/build times
Check whether any builds ran during the compromise window (00:21–03:29 UTC). Correlate GitHub Actions logs, CI timestamps, container image creation times, and SBOM generation logs.
Hunt via network and process telemetry
# Check for C2 traffic
# macOS/Linux
lsof -i -nP | grep sfrclak
lsof -i -nP | grep "142.11.206.73"
# Windows (PowerShell)
netstat -ano | findstr "142.11.206.73"
# Check for residual RAT files
# macOS
ls -la /Library/Caches/com.apple.act.mond
# Linux
ls -la /tmp/ld.py
ls -la /tmp/.* # dot-prefixed hidden files
# Windows (PowerShell)
Test-Path "$env:PROGRAMDATA\wt"Check caches and private registries
The malicious versions were removed from the public npm registry, but they may still exist in local caches or private/proxy registries (JFrog Artifactory, Sonatype Nexus, Verdaccio, AWS CodeArtifact, GitHub Packages, etc.).
# Clear local caches
npm cache clean --force
yarn cache clean
pnpm store prune
Even if your current dependency tree looks clean, don’t stop there. The dropper self-deletes and swaps package.json for a decoy, so post-incident npm audit and manual inspection are not reliable detection methods. Use EDR telemetry, audit logs, process execution history, and network logs.
What to do now
Emergency response checklist
- Determine exposure: Identify any systems that installed axios@1.14.1/0.30.4 or show evidence of
plain-crypto-js. If you find it, treat the host as fully compromised. - Isolate: Remove affected hosts and build artifacts (containers/artifacts) from the network.
- Rotate all credentials: Environment variables, API keys, tokens, SSH keys, cloud credentials, npm tokens, CI secrets—everything. The RAT is designed to steal secrets.
- Block C2 egress: Deny outbound traffic to
sfrclak[.]comand142.11.206.73(including port 8000) at firewalls and egress controls. - Rebuild environments: Prefer full rebuilds from known-clean snapshots/base images over “cleanup on the same system.”
- Fix the lockfile: Pin axios to a known good version (1.14.0 or 0.30.3) and add overrides/resolutions to prevent accidental reintroduction.
- Clear caches thoroughly: Local package caches, CI caches (especially node_modules caches created during the window), private registry caches, and Docker images built during the window.
- Rebuild deterministically: Use
npm ci --ignore-scriptsfor a clean install, verifyplain-crypto-jsis absent, and regenerate SBOMs. - Investigate lateral movement: Use EDR/audit logs to confirm whether suspicious processes or egress occurred and to scope spread.
Example: pinning axios
{
"dependencies": {
"axios": "1.14.0"
},
"overrides": {
"axios": "1.14.0"
}
}
The key idea is to remove ^ and ~ ranges so you don’t silently follow patch releases. In practice, use tools like Dependabot to surface updates, then roll them out through review. Also consider adding plain-crypto-js to your package manager and security tooling blocklists.
How to prevent a repeat
Technical guardrails
- Require lockfiles: In CI, prefer
npm cito enforce lockfile consistency. - Control install scripts: Consider
--ignore-scriptsin build environments. This incident depended entirely on a postinstall hook; disabling scripts would have broken the chain. - Run SCA (dependency scanning) continuously and maintain an up-to-date SBOM.
- Delay brand-new releases: Use features like pnpm’s “minimum release age” and similar cooldown windows to avoid immediately consuming fresh publishes.
- Verify provenance: Check for signed provenance (SLSA-style) and distinguish CI-published releases from direct CLI publishes.
- Monitor egress from build systems: Detect unexpected outbound traffic (new domains/ports) during dependency installation and builds.
- Evaluate tooling such as npq, Snyk, Socket, and similar ecosystem security controls.
Operational and organizational practices
- Keep build metadata (timestamps, dependency hashes) so you can trace “what was built during the compromise window.”
- Define update policies and exception paths for critical, high-reuse dependencies.
- Assume maintainer account compromise happens and design to limit blast radius (network segmentation, least privilege, short-lived secrets).
- Revisit npm token practices. Prefer short-lived tokens or OIDC-based trusted publishing over long-lived classic tokens.
Note for end users
People using web/mobile apps that happen to depend on axios are not typically at direct risk from this incident. The infection vector is the install/build process, not the runtime behavior of an already-built app. The primary risk is to developers, build hosts, and CI/CD pipelines that pulled the malicious versions.
Context: the broader npm supply chain trend
This incident stands out as one of the most operationally sophisticated supply chain attacks in the npm ecosystem. StepSecurity described it as among the most advanced supply chain compromises affecting a top-tier npm package.
It also landed amid a cluster of supply chain activity in late March 2026, including compromises affecting security tooling and developer-facing packages. GTIG assessed the axios incident as independent from the TeamPCP/UNC6780 activity, but Mandiant CTO Charles Carmakal warned that secrets stolen in recent supply chain incidents can enable follow-on compromises for days to months—fueling additional supply chain attacks, SaaS account takeovers, ransomware/extortion, and crypto theft.
Summary
- Axios was compromised on March 31, 2026 (00:21–03:29 UTC). The malicious releases were axios@1.14.1 and axios@0.30.4.
- Google attributed the attack to the North Korea–nexus actor UNC1069 (often linked to the broader BlueNoroff cluster). A newer WAVESHAPER backdoor variant was reported in macOS payloads.
- If you installed/built during the compromise window, respond as if the system is fully compromised.
- Because the dropper self-deletes,
npm auditand manual inspection are not sufficient. Use IOC-based hunting plus EDR/network telemetry. - Response works best as a bundle: isolate → rotate secrets → block C2 → rebuild → clear caches → pin dependencies.
- Prevention: pin versions, consider
--ignore-scriptsin CI, delay fresh releases, verify provenance, monitor egress, and use short-lived publishing credentials.
References
- Google Cloud Blog: North Korea-nexus threat actor compromises widely used Axios npm package
- Datadog Security Labs: Compromised axios npm package delivers cross-platform RAT
- Elastic Security Labs: Inside the Axios supply chain compromise
- StepSecurity: Axios compromised on npm
- Snyk: Axios npm package compromised
- Socket: Supply chain attack on axios
- Wiz: Axios npm distribution compromised in supply chain attack
- SafeDep: Axios compromised — npm supply chain attack via dependency injection
- Semgrep: Axios supply chain incident — indicators of compromise
- Huntress: Supply chain compromise of axios npm package
- Malwarebytes: Axios supply chain attack chops away at npm trust
- GitHub issue: axios@1.14.1/0.30.4 — axios/axios#10604
- GitHub security advisories: axios/axios