Malicious npm Package Exfiltrated Environment Variables at Build Time
A typosquatted npm package installed via a developer's local npm install exfiltrated AWS credentials from CI environment variables.
Overview
A one-word typo pulled in a typosquatted npm package whose install script sent CI's AWS keys to an attacker, who then swapped the site's JavaScript bundle for 6 hours.
What happened
Setting up a new project, a platform developer typed npm install lodash-utils instead of lodash. The package had been published to npm 3 weeks earlier. The developer also added it to the project's package.json without noticing it was not lodash.
How it spread
The postinstall script read process.env, serialized it and sent it to an external endpoint over HTTPS. On the developer's laptop that exposed only a development AWS_PROFILE. In GitHub Actions, the runner had deployment keys in its environment.
- Developer's machine — AWS_PROFILE for development — Little of interest
- CI runner (GitHub Actions) — Deployment access keys — Keys with S3 read/write and CloudFront invalidation stolen
The fix
Stop install scripts from running in CI, and make any key they could reach short-lived and narrow.
Key concepts
- Typosquatting
- Publishing a malicious package under a name that closely resembles a popular legitimate package, relying on developers mistyping the package name.
- Postinstall script attack
- Malicious npm packages that execute arbitrary code via the postinstall lifecycle hook, which runs automatically during npm install.
- Lock file integrity
- package-lock.json or yarn.lock files pin exact package versions and checksums, preventing unexpected package substitution.
- OIDC for CI credentials
- Using OpenID Connect to issue short-lived, scoped tokens to CI jobs rather than long-lived access keys stored as secrets, limiting the blast radius of a credential compromise.
When to use it
- Discussing software supply chain security and npm package hygiene
- Justifying the use of npm audit, lock files, and private registries
- Explaining why CI environment variables should be scoped to specific jobs and not available to all steps
Interview questions
- How do you protect CI/CD pipelines from malicious npm packages?
Sign up free to read the full topic
More War Stories topics
- Blue-Green Deployment That Resulted in Split-Brain Sessions
- Cache Stampede on a Flash-Sale Product Page
- Connection Pool Exhaustion That Brought Down 12 Microservices
- DynamoDB Hot Partition That Throttled a Flash Sale
- Failover to a Lagging Replica Lost 4 Minutes of Orders
- Internal DNS Cache Poisoning That Redirected API Traffic
- N+1 Query Pattern That Collapsed Under Load
- NAT Gateway Port Exhaustion Under Bursty Lambda Traffic
- Node.js Memory Leak That Required Daily Restarts
- Public S3 Bucket Exposed Customer PII for 8 Months
- Silent Data Corruption from an Off-By-One Migration
- Single-Region Dependency That Caused a Global Outage
Start free on Cariara · Coding problems · System design studio