NewsTools & Platforms

The Day Axios Was Compromised: Inside the npm Supply Chain Attack

Axios was compromised on npm on March 31, 2026. Learn impacted versions, timeline, IOCs, how to verify exposure, and incident response steps.

Ibuki Yamamoto
Ibuki Yamamoto
April 1, 2026 7min read

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)

Bottom line: is your project safe?

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 npm install axios yourself.

And on March 31, 2026, axios was compromised on npm.

A threat actor tied to North Korea (UNC1069) took over the npm maintainer account 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.

“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 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.

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:

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.

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-js payload directly
  • @qqbrowser/openclaw-qbot@0.0.130: ships a tampered axios@1.14.1 inside its own node_modules, then triggers plain-crypto-js as 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: osascript execution from $TMPDIR
  • Windows: cscript running a .vbs from %TEMP%
  • Linux: python3 /tmp/ld.py running 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.0 or ^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/null

Verify 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

  1. 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.
  2. Isolate: Remove affected hosts and build artifacts (containers/artifacts) from the network.
  3. Rotate all credentials: Environment variables, API keys, tokens, SSH keys, cloud credentials, npm tokens, CI secrets—everything. The RAT is designed to steal secrets.
  4. Block C2 egress: Deny outbound traffic to sfrclak[.]com and 142.11.206.73 (including port 8000) at firewalls and egress controls.
  5. Rebuild environments: Prefer full rebuilds from known-clean snapshots/base images over “cleanup on the same system.”
  6. 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.
  7. 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.
  8. Rebuild deterministically: Use npm ci --ignore-scripts for a clean install, verify plain-crypto-js is absent, and regenerate SBOMs.
  9. 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 ci to enforce lockfile consistency.
  • Control install scripts: Consider --ignore-scripts in 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 audit and 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-scripts in CI, delay fresh releases, verify provenance, monitor egress, and use short-lived publishing credentials.

References

About the Author

Ibuki Yamamoto
Ibuki Yamamoto

Web scraping engineer with over 10 years of practical experience, having worked on numerous large-scale data collection projects. Specializes in Python and JavaScript, sharing practical scraping techniques in technical blogs.

Leave it to the
Data Collection Professionals

Our professional team with over 100 million data collection records annually solves all challenges including large-scale scraping and anti-bot measures.

100M+
Annual Data Collection
24/7
Uptime
High Quality
Data Quality