Skip to main content
supply-chain npm north-korea malware nodejs threat-intelligence

When npm install Becomes a Weapon: Inside the axios Supply Chain Attack

Sevarity Team

On March 31, 2026, two malicious versions of axios landed on npm and spent roughly three hours as the “latest” tag before anyone pulled them. Axios receives over 180 million downloads per week. That three-hour window was enough to reach developer machines on every continent.

Key Takeaways

  • Attackers used a fake Microsoft Teams call to deliver a RAT to the lead axios maintainer, then used a long-lived npm token to bypass OIDC publishing controls.
  • The malicious dependency [email protected] ran a postinstall hook that delivered platform-specific RATs and self-deleted in ~15 seconds, leaving minimal forensic trace.
  • At least 135 endpoints contacted C2 infrastructure during the 3-hour window (Huntress, 2026).
  • Immediate action: pin to [email protected] (v1.x) or [email protected] (v0.x) and add an overrides block.

How Did Attackers Gain Control of the axios npm Account?

A coordinated social engineering campaign, not a code exploit, gave attackers access to one of npm’s most-downloaded packages in March 2026 (Google Threat Intelligence Group, 2026). The technique mirrors BlueNoroff’s documented playbook against cryptocurrency developers: clone legitimate company branding, build trust over messaging platforms, then deliver malware through a scheduled call.

The attacker built a fake Slack workspace with convincing team profiles and scheduled a Microsoft Teams call under the pretense of a missing software update. During that call, a remote access trojan landed on the maintainer’s machine. With account access secured, the attacker changed the account email to [email protected] and used a long-lived npm token to bypass the project’s OIDC-based publishing pipeline.

Between 00:21 and 03:20 UTC, two backdoored releases went live:

Both versions introduced a single new runtime dependency: [email protected]. The real axios source code was untouched. The entire attack vector was one line added to package.json.

According to the Google Threat Intelligence Group, attackers changed the axios maintainer’s npm account email to [email protected] and used a pre-existing long-lived token to publish malicious releases, bypassing the project’s OIDC controls entirely (Google Threat Intelligence Group, 2026). Every publishing security control on the pipeline became irrelevant once the account was taken.

axios Attack Timeline, March 31, 2026 (UTC)axios Attack Timeline · March 31, 2026 (UTC)← 3-hour exposure window · 135+ endpoints hit C2 →00:0001:0002:0003:0003:30AccountcompromisedMaliciouspkgs livePackagesremovedAttacker eventMitigationExposure windowSources: Huntress; Google TIG (2026)
The malicious axios packages were live for less than 3 hours on March 31, 2026. At least 135 endpoints contacted C2 infrastructure during that window. Sources: Huntress; Google Threat Intelligence Group (2026).

How Did the Malicious Package Execute Code Without Detection?

The malicious dependency used npm’s postinstall hook, a feature npm runs automatically at the end of every install, to execute setup.js with zero user interaction and no visible error output (Unit 42, Palo Alto Networks, 2026). From the outside, the install looked completely normal. That’s the point: this attack didn’t use a zero-day. It used a legitimate npm feature.

Inside setup.js, a two-layer encoding scheme hid the payload: strings were reversed with underscores replaced by padding characters, then Base64-decoded, then XOR’d against the key OrDeR_7077. Once decoded, the script checked the OS and fetched the appropriate payload from C2 infrastructure at sfrclak[.]com:8000.

After delivering the payload, the dropper cleaned up. It deleted setup.js, stripped the postinstall hook from package.json, and replaced the file with a clean stub. The whole sequence finished in about 15 seconds.

The [email protected] dropper completed its full execution chain, OS detection, C2 contact, payload delivery, and self-cleanup, in approximately 15 seconds. It removed setup.js, stripped the postinstall hook, and replaced both with clean stubs, leaving no obvious artifacts for standard forensic scanning (Unit 42, 2026).

Windows

On Windows, the dropper wrote a VBScript to %TEMP%\6202033.vbs, then copied powershell.exe to %PROGRAMDATA%\wt.exe. Renaming PowerShell to wt.exe, the legitimate filename for Windows Terminal, bypasses process-name detections without custom evasion code. A PowerShell RAT ran in a hidden window, and persistence landed in a registry Run key registered as MicrosoftUpdate.

The RAT supported four operator commands: kill, peinject (in-memory .NET injection), runscript, and rundir. It sent system recon data on first contact and beaconed home every 60 seconds.

macOS

An AppleScript downloaded a universal Mach-O binary (x86_64 and ARM64) to /Library/Caches/com.apple.act.mond, mimicking Apple’s internal cache naming. The binary was ad-hoc code-signed to bypass Gatekeeper. Jamf researchers found an internal project name embedded in the binary: macWebT, a direct reference to a module previously documented in BlueNoroff’s RustBucket campaigns.

Linux

Linux targets received a Python RAT at /tmp/ld.py. Unlike the other platforms, the Linux variant established no persistence. That’s not an oversight. CI/CD runners and containers are ephemeral. Persistence is unnecessary when the goal is harvesting credentials from pipeline environment variables, they exist briefly in memory, then disappear.

WAVESHAPER.V2, Cross-Platform RAT CapabilitiesWAVESHAPER.V2, Cross-Platform CapabilitiesCapabilityWindowsmacOSLinuxPayload typePowerShell RATMach-O binaryPython RATPersistenceRegistry Run keyLaunchAgentNoneC2 beacon interval60 seconds60 seconds60 secondsEvasion methodRename to wt.exeAd-hoc code signEphemeral envPrimary targetsDev workstationsDev workstationsCI/CD pipelinesSources: Unit 42; Google TIG; Microsoft Security Blog (2026)
The Linux variant skipped persistence entirely, CI/CD environments are ephemeral, so the goal was harvesting in-memory pipeline credentials, not long-term access. Sources: Unit 42; Google Threat Intelligence Group; Microsoft Security Blog (2026).

Who Is Behind the axios Supply Chain Attack?

Multiple independent research groups reached the same conclusion: a North Korea-linked, financially motivated threat actor with a documented history of targeting developer tooling (Microsoft Security Blog, 2026). Google Threat Intelligence Group attributed the attack to UNC1069, active since 2018. Microsoft attributed overlapping activity to Sapphire Sleet, which maps to BlueNoroff and STARDUST CHOLLIMA across vendor naming systems. The malware, tracked as WAVESHAPER.V2, is an evolution of backdoor tooling with documented prior DPRK attribution.

The C2 server (sfrclak.com, resolving to 142.11.206.73) connected to an AstrillVPN exit node with historical ties to UNC1069 infrastructure. One detail stands out: the campaign identifier embedded in the C2 path was /6202033. Reversed, that reads 3302026, 3-30-2026, one day before the attack went live.

In April 2026, Google Threat Intelligence Group attributed the axios npm compromise to UNC1069, a financially motivated North Korea-nexus actor active since 2018. Microsoft attributed overlapping activity to Sapphire Sleet. The malware, designated WAVESHAPER.V2, shares tooling lineage with BlueNoroff’s RustBucket macOS campaigns (Google Threat Intelligence Group, 2026).

Why Should Every JavaScript Developer Care?

Developer workstations and CI/CD pipelines accumulate credentials, and at least 135 endpoints called back to C2 infrastructure during the three-hour exposure window, within Huntress’s partner network alone (Huntress, 2026). The RAT’s capability set was purpose-built to extract npm tokens, SSH keys, AWS access keys, GitHub Personal Access Tokens, and database passwords from .env files.

Here’s what surprises most developers: transitive dependencies amplified the blast radius far beyond direct axios users. Organizations that never directly referenced axios were still exposed if any package in their dependency tree resolved through the compromised versions. That’s not a niche edge case, it’s how most real-world dependency graphs work.

Think about it this way: if your CI/CD pipeline runs npm install on any project with indirect axios usage, you were in scope. You didn’t need to import axios yourself.

Within Huntress’s partner network alone, at least 135 endpoints contacted C2 infrastructure at sfrclak.com during the three-hour axios exposure window. Transitive dependency resolution extended the blast radius to any project with indirect axios usage, direct imports weren’t required for exposure (Huntress, 2026).

What Should You Do If Your Environment Was Exposed?

If your lockfile or node_modules contains [email protected], [email protected], or any version of plain-crypto-js, treat the affected host as compromised, not potentially compromised.

  1. Don’t try to clean the machine in place. Rebuild from a known-good image.
  2. Rotate all credentials accessible from the affected system: npm tokens, SSH keys, AWS access keys, API keys, GitHub tokens, database passwords.
  3. Pin axios to a safe version in package.json:
    • v1.x branch: "axios": "1.14.0"
    • v0.x branch: "axios": "0.30.3"
  4. Add a package override to block transitive resolution:
    "overrides": {
      "plain-crypto-js": "npm:[email protected]"
    }
  5. Block outbound traffic to sfrclak.com and 142.11.206.73 on port 8000.
  6. Audit CI/CD logs for npm install steps that ran between 00:21 and 03:20 UTC on March 31, 2026.

How Can You Prevent the Next Supply Chain Attack?

This attack is a case study in why postinstall scripts are dangerous at scale, and there are specific controls that would have blocked it, or at least detected it faster (axios GitHub Issue #10636, 2026). None of these require exotic tooling. They’re configuration changes.

Use npm ci --ignore-scripts in pipelines. Postinstall hooks are rarely needed for library dependencies. They’re an automatic code execution vector with no review gate. Disabling them removes the entire attack surface this campaign relied on.

Commit and enforce your lockfile. npm install can silently resolve newer versions. npm ci can’t. The lockfile is your integrity anchor, treat it like one.

Set a minimum release age for new versions. Tools like Socket and npm’s own configuration let you quarantine new releases for 48–72 hours, giving automated systems time to flag malicious packages before your build ingests them.

Move to OIDC-based publishing for any package you maintain. Long-lived npm tokens are a single point of failure. The compromised maintainer had one, that’s what bypassed the project’s own OIDC controls. OIDC tokens are scoped to specific workflows and expire automatically.

Treat developer workstations with a server-level threat model. The machine that builds the software often holds more valuable credentials than the production systems it deploys to.

The axios attack exploited postinstall, a legitimate npm feature, to run malicious code automatically during package install with no user confirmation. Using npm ci --ignore-scripts in CI/CD pipelines eliminates this execution vector entirely, with no functional impact on library dependencies (axios GitHub Issue #10636, 2026).

Indicators of Compromise

Malicious packages:

Network:

  • Domain: sfrclak[.]com
  • IP: 142.11.206.73
  • Port: 8000
  • C2 path: /6202033
  • User-Agent: mozilla/4.0 (compatible; msie 8.0; windows nt 5.1; trident/4.0)

File artifacts:

  • Windows: %PROGRAMDATA%\wt.exe, %PROGRAMDATA%\system.bat
  • macOS: /Library/Caches/com.apple.act.mond
  • Linux: /tmp/ld.py

Attacker accounts:

Frequently Asked Questions

Is axios safe to install today?

Yes. The malicious versions ([email protected] and [email protected]) were removed from npm within three hours of publication on March 31, 2026. Pin to [email protected] (v1.x) or [email protected] (v0.x) and add an overrides block to prevent transitive resolution of plain-crypto-js.

How do I check if my project pulled the malicious version?

Run npm ls axios and search your package-lock.json for [email protected], [email protected], or [email protected]. If any appear, treat that host as compromised and rotate all credentials the machine could access, npm tokens, SSH keys, cloud access keys, database passwords.

What is a postinstall hook and why is it dangerous?

A postinstall hook is a script npm runs automatically after a package installs, no user prompt, no confirmation required. It’s a legitimate feature for build steps and native module compilation. It’s also an arbitrary code execution vector. The axios attack ran its entire payload delivery and self-cleanup through this hook in about 15 seconds. Running npm ci --ignore-scripts disables it.

Could this happen to any npm package?

Any package whose maintainer account is compromised is a valid vector. The attacker chose axios specifically for scale, 180 million weekly downloads means broad reach from a single poisoned release. The underlying technique (social engineering → account compromise → dependency injection → postinstall execution) applies to any package on npm.

What’s the difference between npm install and npm ci for security?

npm install can silently resolve newer package versions, bypassing your lockfile in some scenarios. npm ci installs exactly what’s in package-lock.json, no deviation. In automated pipelines, npm ci --ignore-scripts adds a second layer by disabling postinstall hooks entirely. Use npm ci for all automated builds.

References

Secure Your Operations

Ready to identify critical vulnerabilities before threat actors do?

Request a Quote