Lifecycle Scripts: The #1 Supply‑Chain Blindspot in PRs: Detect and Block in Review

Lifecycle scripts like preinstall
, prepare
, and postinstall
can execute arbitrary code during dependency installation. They are convenient for building native addons or generating artifacts—but they are also a prime vector for supply‑chain attacks. This guide shows how to surface lifecycle scripts directly in code review, adopt safe CI defaults, and block risky changes before they merge.
What Are Lifecycle Scripts?
In npm/pnpm/Yarn, packages can declare script hooks that run automatically during installation. Common hooks: preinstall
, install
, postinstall
, andprepare
. Any of these may run in your CI or on developer machines depending on the package manager and settings.
Why They Are a Blindspot
- They run outside your application runtime—traditional scanners often miss them.
- They execute during install, when CI secrets and network are commonly available.
- They can arrive via transitive deps; PRs may only show a lockfile bump.
Reviewer Checklist (Fast)
- Scan lockfile diffs for new packages, owner changes, and native addons.
- Search
package.json
files (including transitive) for lifecycle scripts. - Flag packages that download binaries or reach out to the network.
- Confirm whether CI runs with
--ignore-scripts
and has an allow‑list policy.
Quick Commands You Can Drop Into Reviews
Find lifecycle scripts in the repo:
# Search top-level workspace packages
rg -n ""(preinstall|install|postinstall|prepare)"s*:" --glob "**/package.json" --hidden
# If lockfile changed, enumerate new/updated packages (npm)
git diff HEAD~1 -- package-lock.json | rg '"(version|name)"'
# pnpm: list packages that declare lifecycle scripts
pnpm list --depth Infinity --json | jq '.[] | select(.manifest.scripts | type=="object") | {name, version, scripts: (.manifest.scripts|keys)}'
Safe Defaults in CI
Adopt a baseline that prevents surprise execution and allows exceptions when needed.
# npm
npm ci --ignore-scripts --fund=false --audit=false
# If a package truly needs a build step:
npm rebuild --ignore-scripts
# pnpm
pnpm install --frozen-lockfile --ignore-scripts
# Yarn Berry
# .yarnrc.yml
enableScripts: false
Minimal GitHub Actions Template
name: ci
on: [pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: '20', cache: 'npm' }
- run: npm ci --ignore-scripts --fund=false --audit=false
- run: npm test --ignore-scripts
# Optional: fail PR if new lifecycle scripts appear
- run: |
rg -n ""(preinstall|install|postinstall|prepare)"s*:" --glob "**/package.json" --hidden | tee lifecycle-scripts.txt
test ! -s lifecycle-scripts.txt || (echo 'Found lifecycle scripts. Review required.' && exit 1)
Policy: When to Allow, When to Block
- Allow only for vetted packages that truly need native builds (e.g.,
sharp
). - Block network access during install; fetch artifacts from pinned, internal mirrors.
- Require explicit approval when a PR introduces new lifecycle scripts.
Automating the Review
The fastest path is to surface these signals inline on the PR. Propel’s code review AI highlights lifecycle scripts, risky lockfile diffs, and owner changes as comments you can act on immediately—and enforces merge gates when desired.
Takeaways
- Default to
--ignore-scripts
in CI. - Make lifecycle scripts visible in every dependency PR.
- Establish a lightweight allow‑list and approval flow.
Ready to Transform Your Code Review Process?
See how Propel's AI-powered code review helps engineering teams ship better code faster with intelligent analysis and actionable feedback.