Safeguard
Supply Chain•

Why is scanning after install too late for malicious packages?

Install time scripts can run before any scan does. For malicious packages, the decision has to come before download or install, not after.

Safeguard Security Team
3 min read

Scanning after install can be too late because packages may run code while installing. If a malicious package executes during install, a later scan only reports what already happened. For that threat the control has to act before download or before install, through a proxy, an allowlist or disabled install scripts.

What the documentation says

npm's configuration reference describes an option, ignore-scripts, which when true stops npm running scripts specified in package.json files. Its default is false, so scripts run by default. pip's secure installs page says that by default pip performs no checks against remote tampering and involves running arbitrary code from distributions. It names two ways to tighten that: hash checking mode, and disallowing source distributions with an option that accepts only binary packages.

You do not need a specific incident to see the timeline problem. The sequence is simple: resolve, download, install (code may run), then your scan. Anything that happens in the third step is already done.

Two threat types, two controls

ThreatWhen it bitesBest control point
Known vulnerable versionWhen the vulnerable code runs in your productScan on pull request, build and schedule
Malicious package with install time codeAt install, on whichever machine installs itBefore download or install
Tampered package in transitAt downloadHash checking, signatures
Typosquat or lookalike nameAt the moment someone types the nameIDE hint, proxy or allowlist rule

A vulnerability scan is the right tool for the first row. It is the wrong tool for the second.

Controls that act before install

  1. A registry proxy or approved package list. The decision happens at request time. See approved package allowlist or scan on install.
  2. Disable install scripts by default in CI and on build machines, and enable them per package where truly needed. Test your builds, since some packages rely on them.
  3. Hash and pin. With pip, hash checking mode requires every requirement to be pinned and hashed, which blocks silent substitution.
  4. Minimum release age. Holding very new versions for a short period gives the community time to flag bad ones. See minimum release age policies.
  5. Isolated runners. Run installs in ephemeral environments with no long lived secrets, so any code that does run has little to take.

What still belongs after install

Do not drop post install scanning. It finds known vulnerabilities, licence issues and drift. It just cannot be your only answer to malicious code, because it is not designed to run in time.

A sensible order

Start with ephemeral, low privilege CI runners and a decision on install scripts. Add a proxy or allowlist as the next step. Keep the scanning stages you already have.

Where Safeguard fits

Safeguard provides dependency scanning, SBOM generation and gates for the known vulnerability side, and policies you can apply to what your pipelines accept. Try a free scan at gold.safeguard.sh/scan.

Quick check

Does disabling install scripts break builds?

Some packages need them, for example to build native code. Disable by default, then allow the specific packages that require it, and test.

Is a vulnerability scan useless against malicious packages?

Not useless once a package is reported, but it relies on known data and runs after install. Pair it with a pre install control.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.