CriticalSupply chainPatch available

axios npm hijack: versions 1.14.1 and 0.30.4 installed a North Korean RAT via plain-crypto-js

A hijacked maintainer account published axios 1.14.1 and 0.30.4 with a dependency that installs a remote access trojan. Check lockfiles for plain-crypto-js.

Published
Updated
Ecosystem
npmCI/CD
Fixed in
Malicious versions removed; last clean releases before the attack were 1.14.0 and 0.30.3
Exploitation
Yes. Malicious versions were live on npm for about three hours on 31 March 2026

What happened

On 31 March 2026, an attacker used the lead axios maintainer’s npm account to publish two malicious releases (axios post-mortem):

  • 00:21 UTC: axios@1.14.1, with a new dependency, plain-crypto-js@4.2.1.
  • About 01:00 UTC: axios@0.30.4, with the same dependency.
  • 03:15 UTC: both versions removed from npm. plain-crypto-js followed at 03:29 UTC.

The attacker prepared the ground the day before. A clean plain-crypto-js@4.2.0 went up at 05:57 UTC on 30 March, so the name had a short history before the bad 4.2.1 arrived (axios post-mortem). The name imitates the real crypto-js library. Google notes the two axios lines typically see over 100 million and 83 million weekly downloads (Google Threat Intelligence).

The maintainer says the account fell to a targeted social-engineering campaign that started about two weeks earlier. The attacker posed as a company founder, invited him to a fake Slack workspace and a Teams call, and got him to install a “missing” update that was a RAT. Two-factor authentication was on, but did not help once the attacker controlled his machine (axios post-mortem). Google says the account’s email was changed to an attacker-controlled address (Google Threat Intelligence).

Attribution. Google attributes the attack to UNC1069, a financially motivated North Korea-nexus group (Google Threat Intelligence). Microsoft attributes it to Sapphire Sleet, a North Korean state actor (Microsoft). CISA published an alert on 20 April 2026 but does not name an actor (CISA).

How the payload works

All details below are from Google Threat Intelligence unless stated.

  1. plain-crypto-js declares "postinstall": "node setup.js", so the dropper runs during npm install. Google calls it SILKBELL.
  2. It downloads a platform-specific second stage from sfrclak[.]com on port 8000 (IP 142.11.206.73): - macOS: a binary at /Library/Caches/com.apple.act.mond - Linux: a Python backdoor at /tmp/ld.py - Windows: a copy of PowerShell at %PROGRAMDATA%\wt.exe, a script in %TEMP%, and persistence through %PROGRAMDATA%\system.bat and a MicrosoftUpdate Run key
  3. The backdoor, WAVESHAPER.V2, beacons every 60 seconds and can list files, run scripts and inject binaries.
  4. The dropper then deletes itself and restores a clean-looking package.json. The node_modules/plain-crypto-js folder stays behind, which is why it is the best sign of infection.

Am I affected?

You are affected only if an install resolved one of the two bad versions between 00:21 and 03:15 UTC on 31 March 2026. A lockfile already pinned to a clean version, with no fresh install in that window, was safe (axios post-mortem).

bash
# Lockfiles: plain-crypto-js should never appear
grep -nE 'plain-crypto-js' package-lock.json npm-shrinkwrap.json yarn.lock pnpm-lock.yaml bun.lock 2>/dev/null

# The resolved tree: look for axios 1.14.1 or 0.30.4
npm ls axios plain-crypto-js --all 2>/dev/null

# The folder left behind in any project on this machine
find / -type d -path '*node_modules/plain-crypto-js' 2>/dev/null

# Your npm cache, which may still hold the tarball
grep -rl 'plain-crypto-js' ~/.npm/_cacache/index-v5 2>/dev/null | head

The axios post-mortem gives a one-line lockfile check too, grep -E "axios@(1\.14\.1|0\.30\.4)|plain-crypto-js", but package-lock.json and yarn.lock store the version on a separate line from the name, so the plain-crypto-js match and npm ls are the reliable signals.

Then look for the second stage on any machine that ran an install in the window:

bash
ls -la /Library/Caches/com.apple.act.mond 2>/dev/null   # macOS
ls -la /tmp/ld.py 2>/dev/null                           # Linux

On Windows, check for %PROGRAMDATA%\wt.exe and %PROGRAMDATA%\system.bat. Search DNS and proxy logs for sfrclak.com. Remember npx and one-off CI jobs: they resolve dependencies without leaving a lockfile behind, so check CI network logs for the window too (axios post-mortem).

What to do now

  1. Assume compromise if plain-crypto-js was installed. Revert the machine or runner to a known-good state rather than cleaning it in place (Google Threat Intelligence).
  2. Rotate credentials. Version-control tokens, CI/CD secrets, cloud keys, npm tokens and SSH keys. For short-lived CI jobs, rotate every secret injected into the affected run (CISA).
  3. Upgrade axios. CISA and the maintainers named 1.14.0 and 0.30.3 as clean. They are not the end of the story: many axios security advisories have been published since April 2026. As of 1 November 2026, npm lists 1.21.0 as latest and 0.34.0 for the 0.x line (npm). Move to a current release and commit the lockfile.
  4. Clear caches. Clear npm, yarn and pnpm caches on workstations and build servers, and purge the versions from any internal registry mirror (Google Threat Intelligence).
  5. Turn off install scripts and add a delay. CISA recommends ignore-scripts=true and min-release-age=7 in .npmrc (CISA). Either would have stopped this attack.
  6. If you publish packages, publish from CI with trusted publishing (OIDC), not from a laptop. The axios maintainer’s own lesson was that publishing from a personal account “was a risk that could have been avoided” (axios post-mortem).

Why this is part of the Vulnpocalypse

axios had no code bug here. A state-backed group spent two weeks on one person, then reached a large share of the JavaScript ecosystem in three hours. Detection depended on community members noticing; the maintainers say they had no automated way to spot an unauthorised publish. When attackers can do this to a package with this many installs, every dependency update is a trust decision. Install scripts off, a release-age delay and a committed lockfile turn that decision back over to you.

Sources