Skip to main content
npm Install Scripts Disabled: The Incident That Never HappenedIncident
4 min readFor Security Engineers

npm Install Scripts Disabled: The Incident That Never Happened

What Happened

Nothing broke. No breach occurred. No credentials leaked. That's the point.

GitHub announced that npm version 12, releasing next month, will disable install scripts by default. This is a preemptive architectural change, not a response to a specific incident. The decision stems from a clear pattern: install-time lifecycle scripts represent what GitHub calls the "single largest code-execution surface in the npm ecosystem."

Every time you run npm install, you're potentially executing code from hundreds of transitive dependencies. Most developers don't audit these scripts. Most CI/CD pipelines run them automatically. And attackers know this.

Timeline

This isn't a traditional incident timeline—it's a threat model that's been exploited repeatedly:

The Attack Pattern:

  1. Attacker compromises a maintainer account or publishes a typosquatted package.
  2. Malicious code sits in preinstall, postinstall, or prepare hooks.
  3. Developer runs npm install (or CI pipeline does it automatically).
  4. Script executes with the developer's permissions—access to environment variables, AWS credentials, SSH keys, source code.
  5. Exfiltration happens before anyone notices the package.

Notable Examples:

  • The event-stream compromise (2018): malicious code in install scripts harvested cryptocurrency wallet credentials.
  • The ua-parser-js incident (2021): install scripts deployed cryptocurrency miners.
  • Dozens of typosquatting packages caught harvesting environment variables during installation.

GitHub's change doesn't respond to one incident. It addresses the structural vulnerability that makes all these attacks possible.

Which Controls Failed or Were Missing

The current npm default configuration fails multiple defense-in-depth principles:

Implicit Trust in Transitive Dependencies
When you install a package, you're trusting not just that package but every dependency it pulls in. Your package.json might list 15 direct dependencies, but npm install executes scripts from 400+ packages. You didn't review 385 of them.

No Principle of Least Privilege
Install scripts run with your full user permissions. They can read your .aws/credentials file, your .ssh directory, your environment variables containing API keys. There's no sandbox, no permission model, no "this script needs network access" prompt.

Automatic Execution Without Consent
The current default is opt-out, not opt-in. Scripts run unless you explicitly disable them with --ignore-scripts. Most developers don't know this flag exists. Most CI/CD configurations don't use it.

No Audit Trail
When an install script runs, there's no clear log of what it did. It might have sent your credentials to an external server. It might have modified your source code. Unless you're running with verbose logging and actively monitoring, you won't know.

What the Relevant Standards Require

PCI DSS v4.0.1 Requirement 6.3.2:
"Software development personnel are trained at least once every 12 months on secure coding techniques, including how to avoid common coding vulnerabilities, and on how to use secure coding techniques."

Supply chain security is a secure coding issue. If your training doesn't cover dependency verification and the risks of automatic script execution, you're not meeting this requirement. The npm v12 change forces this conversation.

NIST 800-53 Rev 5 Control SA-12 (Supply Chain Protection):
"Employ [Assignment: organization-defined controls] to protect against supply chain threats to the system, system component, or system service."

The current npm default provides no protection. You need organizational controls that define:

  • Which dependencies are approved.
  • How install scripts are reviewed.
  • What happens when a new dependency appears in the tree.

ISO/IEC 27001:2022 Annex A.8.30 (Outsourced Development):
"The organization shall supervise and monitor the activity of outsourced system development."

Every npm package is outsourced development. You're running code written by strangers. The standard requires supervision and monitoring. Automatic script execution makes both impossible.

OWASP Top 10 2021: A06 - Vulnerable and Outdated Components:
This category explicitly covers supply chain risks. The guidance states: "Only obtain components from official sources over secure links."

But "official sources" doesn't mean "safe sources." The npm registry is official. Malicious packages published there are still official. You need verification beyond "it's on npm."

Lessons and Action Items for Your Team

Before npm v12 Releases:

  1. Audit your current install script usage. Run npm explore <package> -- cat package.json for your top dependencies. Look at the scripts section. What's in preinstall, postinstall, prepare? If you can't explain what a script does, you shouldn't be running it.

  2. Test with --ignore-scripts now. Run your builds with npm install --ignore-scripts and see what breaks. Document which packages legitimately need install scripts (native modules that compile C++ code, for example). This is your allowlist.

  3. Update your CI/CD pipelines. Add --ignore-scripts to all npm install commands. Use npm rebuild for specific packages that need compilation. This gives you explicit control instead of implicit trust.

  4. Implement dependency review gates. When a PR adds a new dependency, your review process should include:

    • Check the package's install scripts.
    • Review the maintainer's history.
    • Verify the package name (typosquatting check).
    • Document why this dependency is approved.

After npm v12 Releases:

  1. Create an install script policy. Define which types of scripts are acceptable:

    • Native module compilation: usually acceptable.
    • Code generation: review case-by-case.
    • Network requests during install: default deny.
    • File system operations outside node_modules: default deny.
  2. Use .npmrc to enforce your policy. Set ignore-scripts=true in your project's .npmrc file. Use npm config set ignore-scripts true globally on developer machines. Require explicit opt-in via --ignore-scripts=false when needed.

  3. Monitor for script execution attempts. When npm v12 blocks a script, it will log a warning. Treat these warnings as security events. Investigate why a package tried to run a script and whether it's legitimate.

The npm v12 change shifts the default from "trust everything" to "verify first." Your incident response plan should include dependency verification. Your threat model should include compromised packages. Your training should cover supply chain attacks.

This isn't about one incident. It's about preventing the next thousand.

Topics:Incident

You Might Also Like