Togoder security

How-to

How to detect malicious postinstall scripts

To detect malicious postinstall scripts, list every package in your lockfile that has install scripts (package-lock.json marks them with hasInstallScript), read what each script runs, and look for network calls, environment-variable reads, decoded payloads and downloaded binaries. Block scripts by default and allow only the packages that need them.

Detection2 min readUpdated By Togoder Security

Key takeaways

  • npm runs preinstall, install and postinstall for every package in the tree, including transitive dependencies.
  • package-lock.json flags packages with install scripts; npm query can list them in the installed tree.
  • Red flags: script files that read process.env or ~/.npmrc and make network requests, curl | sh, base64 decoded into eval, and scripts added in a patch release.
  • pnpm 10 and Bun do not run dependency scripts unless allowed; npm and Yarn need a setting.
  • Payloads can also run on require, so reviewing scripts alone is not enough.

Step 1: List packages with install scripts

From the lockfile, without installing anything:

jq -r '.packages | to_entries[] | select(.value.hasInstallScript) | .key' package-lock.json

From an installed tree (npm 8.16 or later):

npm query ":attr(scripts, [postinstall])" | jq -r '.[].name'
npm query ":attr(scripts, [preinstall])" | jq -r '.[].name'

For a package you have not installed yet:

npm view some-package scripts

Step 2: Read the scripts and the files they run

The script entry is usually a one-liner such as node install.js. The interesting part is the file it runs. Download the tarball without running anything and read it:

npm pack some-package@1.2.3
tar -xzf some-package-1.2.3.tgz
cat package/package.json | jq .scripts
less package/install.js

Step 3: Red flags

  • Reads of process.env, ~/.npmrc, ~/.ssh, cloud credentials or browser profiles, combined with any network request.
  • curl ... | sh, wget, powershell -enc or a download from a raw IP address or paste site.
  • Buffer.from(..., 'base64') or long hex strings fed into eval, new Function or child_process.
  • A script that installs another runtime or tool and runs it, or downloads a secret scanner. The Shai-Hulud worm's second wave did exactly this (details).
  • A script that appeared in a patch release when earlier versions had none: compare with npm diff --diff=pkg@1.2.2 --diff=pkg@1.2.3.
  • Writes outside the package directory, such as to shell profiles, cron, or .github/workflows.

Legitimate install scripts mostly compile native code (node-gyp rebuild) or download a prebuilt binary from the project's own releases. Even those deserve a look at where they download from.

Step 4: Block scripts by default

# npm: per install, or for good
npm ci --ignore-scripts
npm config set ignore-scripts true

# Yarn (Berry): .yarnrc.yml
enableScripts: false

# pnpm 10+: dependency scripts are off unless allowed in package.json
"pnpm": { "onlyBuiltDependencies": ["esbuild"] }

# Bun: only packages in trustedDependencies (plus Bun's default list) run scripts
"trustedDependencies": ["esbuild"]

The full background is in npm install scripts security.

Step 5: Automate it across the whole tree

Reading every install script by hand works for a handful of packages. For the whole lockfile, and for code that runs on require rather than at install, upload the lockfile to Togoder Security. An AI model reads every file of every package, install scripts included, and reports what the code does with a file and line for each finding.

Frequently asked questions

How do I find which npm packages have postinstall scripts?

Filter package-lock.json for entries with hasInstallScript: true, or run npm query ":attr(scripts, [postinstall])" in an installed project. For a single package, npm view <name> scripts shows them.

Is --ignore-scripts enough to stay safe?

It stops install-time payloads, which is where most npm malware runs, but not code that runs when the package is required or bundled into a browser app.

Can a malicious postinstall script be detected automatically?

Yes. Rule-based tools such as GuardDog look for known patterns, and Togoder Security has an AI model read the script and the files it runs, flagging credential reads, network exfiltration and decoded payloads.