Safeguard
Supply Chain•

What is lockfile poisoning and which package manager settings catch it?

Lockfile poisoning slips a changed resolved URL or version into a pull request. What it is, and what pnpm trustLockfile and Yarn hardened mode do about it.

Safeguard Security Team
4 min read

Lockfile poisoning means a pull request edits a lockfile so it points at different code than the manifest suggests, such as another source URL, hash or version, while the visible diff in package.json looks harmless. Defenses are review of the lockfile diff, immutable installs in CI, and package manager checks that re-verify entries.

How the attack is shaped

A lockfile is generated, so reviewers skim it. That habit is the opening. A contributor can hand-edit an entry so a package resolves to a different location or a version published under weaker rules than your policy allows. If CI runs a plain install and trusts what the file says, the edit takes effect.

This is a threat mainly for repositories where people outside your circle of trust can open pull requests, such as public open source projects. It is less of a worry when every commit comes from an employee you know, though stolen accounts exist.

What the tools document

Two package managers describe explicit verification features.

pnpm. After install, pnpm re-applies minimumReleaseAge and trustPolicy to every entry in the loaded lockfile. The trustLockfile setting (v11.3.0, default false) skips that verification pass and treats the lockfile as already trusted. The docs warn that a poisoned lockfile, one authored under a weaker policy than CI enforces, can slip through, and say to leave it false whenever outside collaborators can edit the lockfile.

Yarn. enableHardenedMode makes Yarn query the remote registries and check that the lockfile content matches the remote information. It is slower, so the docs say to run it on branches managed by people outside your circle of trust, and Yarn turns it on automatically for GitHub pull requests from public repositories unless you set it to false.

npm. The npm docs describe npm ci as failing when package.json and package-lock.json disagree, and it never writes to either file. That catches drift, not a lockfile that is internally consistent but points somewhere new.

A review routine that works

  1. Run the frozen install in CI: npm ci, the pnpm frozen lockfile option, or Yarn immutable installs. See frozen lockfile flags compared.
  2. Keep pnpm trustLockfile off, and turn on Yarn hardened mode for untrusted pull requests.
  3. Make lockfile changes visible: a pull request that changes the lockfile without changing the manifest deserves a question. Our guide to what to check in a lockfile diff lists the fields.
  4. Look at resolved source hosts and integrity values for any entry that changed.
  5. Gate the merge on a dependency check, not on reading alone.

Try it yourself

Click through it at your own pace, or open it full screen. Look for how a pull request check reports a result before the merge.

Where Safeguard fits

Safeguard's dependency scanning reads the lockfile that your build resolves, and policies and gates can fail a pull request that adds or changes a component against rules you set. That puts a check beside human review. A free scan is at https://gold.safeguard.sh/scan.

Quick check

Does npm ci stop a poisoned lockfile?

Not by itself. It fails when the lockfile and package.json disagree and never rewrites the lockfile, but a lockfile edited consistently still installs what it says.

When is Yarn hardened mode on?

Yarn enables it automatically on GitHub pull requests from public repositories. You can turn it on elsewhere or set it to false in your yarnrc file.

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.