Safeguard
Developer Tools•

What is a lockfile and does it stop supply chain attacks?

A lockfile records the exact package versions you installed. It blocks surprise updates but does not stop every supply chain attack. Here is how to use it.

Safeguard Security Team
7 min read

A lockfile is a file that records the exact version of every package your project installed, so everyone gets the same ones. It helps stop surprise updates from sneaking in, but it does not stop a supply chain attack if a bad version is already locked in.

TL;DR

  • A lockfile freezes your package versions so installs are repeatable.
  • It protects you from picking up a new bad release by accident.
  • It does not clean out a bad version you already locked, and it does not check that a package is safe.
  • Use it together with npm ci or a similar strict install, and review changes to it like you review code.

Definition: A lockfile is an automatically generated file, such as package-lock.json in the npm ecosystem, that lists the exact versions of all packages in your project, including packages used by your packages. Committing it to your repository means teammates and build servers install the same tree.

Why do projects need a lockfile?

Most projects do not ask for an exact version of each package. They ask for a range, such as "version 4.1 or newer within the same major release." That is convenient. Fixes arrive on their own. But it means two installs on two different days can give two different results.

Think of a recipe that says "some flour." Today you get one bag. Next month you get a different bag. A lockfile changes the recipe to "this exact bag, from this exact shelf."

The npm documentation describes the file this way: it describes the exact tree that was generated, so later installs produce identical trees, regardless of newer releases. It is intended to be committed to source repositories, and the documentation lists several purposes, including making sure teammates, deployments and continuous integration install exactly the same dependencies, and showing changes in readable diffs. A diff is a view of what changed between two versions of a file.

What does a lockfile look like in practice?

Here is a tiny, invented snippet to show the idea. It is not from a real project.

{
  "name": "demo-app",
  "lockfileVersion": 3,
  "packages": {
    "node_modules/example-lib": {
      "version": "2.4.1",
      "resolved": "https://registry.example.com/example-lib/-/example-lib-2.4.1.tgz",
      "integrity": "sha512-EXAMPLE"
    }
  }
}

Three parts matter. The version is the exact one installed. The resolved line says where it came from. The integrity line is a fingerprint, so a changed file can be noticed. You do not need to read these by hand. You need to know they exist so you can spot changes.

How does a lockfile help against attacks?

A lockfile helps in three ways.

  1. It stops silent drift. If an attacker publishes a bad version 2.4.2 tomorrow, a project locked to 2.4.1 does not pull it by accident.
  2. It makes changes visible. To move to 2.4.2, someone must update the lockfile, and that change appears in a pull request that a person can review.
  3. It makes builds repeatable. If something goes wrong, you can rebuild the exact same set later and compare.

For this to work, your build must actually use the lockfile. The npm documentation says that npm ci installs from the lockfile, never writes to package.json or the lockfile, and exits with an error if the two disagree. A plain npm install can update the lockfile. So in pipelines, prefer the strict command.

Python has a similar idea. The pip documentation describes hash checking mode, where hashes embedded in a requirements file protect against remote tampering. It also says the mode is all or nothing: giving a hash to any one requirement turns it on for all of them.

For the wider picture, see what is dependency pinning and our post on why pinning alone is not enough.

What does a lockfile not do?

SituationDoes the lockfile help?Why
A bad version is published after you lockedYesYou stay on the old version until you choose to update
You already locked a bad versionNoThe lockfile faithfully installs the bad one
You update and take a bad versionNoThe file now records the bad version
A package you add is a lookalike of a real oneNoThe lockfile records whatever you added
A legitimate package has a known flawNoA lockfile does not judge safety
Your build ignores the lockfileNoThe protection never applied

The key point: a lockfile is a record, not a judge. It keeps a good state good. It cannot make a bad state good.

Worked example: when does the lockfile save the day?

All numbers and package names here are invented to illustrate the idea.

A team has a project with 300 packages. On Monday at 10:00 a bad version of a package called "tinyformat" is published. On Monday at 14:00, it is flagged and removed.

  • Project A uses a lockfile and installs with the strict command. A build at 11:00 uses the locked version. Not affected.
  • Project B has a lockfile but its pipeline runs a plain install, which can change the file. The build at 11:00 pulls the bad version. Affected.
  • Project C has no lockfile. Any build in the window pulls the bad version. Affected.

Same package, same time window, three different outcomes. Projects A, B and C differ only in how they install. That is why "we have a lockfile" is not the same as "our builds use it."

How do you update safely with a lockfile?

Locking does not mean never updating. Old versions get security fixes too, and sitting still is a risk. A sensible routine:

  1. Update on a schedule, such as weekly, in one pull request per batch.
  2. Read the lockfile diff. Look for new packages, removed packages and changed sources.
  3. Hold brand new versions for a few days when it is not an urgent fix. See dependency cooldown periods.
  4. Run your tests and a scan before merging.
  5. Merge, and let the strict install use the new file.

How can Safeguard help?

Safeguard is a software supply chain security platform. SBOM and dependency scanning reads your lockfiles and builds the list of what your project actually uses, including indirect packages. Policies and gates can check pull requests that change dependencies. Reachability analysis helps you decide which updates matter most. Autonomous remediation with fix pull requests is available, off by default with every category on Manual.

The Safeguard CLI can scan from a terminal or CI and can also write code, so you can ask it to prepare a fix and then review it as you would any change. Try the free scan at gold.safeguard.sh/scan.

Try it yourself

In the demo, follow how a vulnerable package is fixed by moving to a safer version. Look at what changes and what stays the same.

Click through it at your own pace, or open it full screen.

Quick check

Should I commit the lockfile to my repository?

Yes, for applications. The npm documentation says the file is intended to be committed so teammates and build servers install the same tree. For libraries, check your package manager's advice.

Is npm ci really different from npm install?

Yes. According to the npm documentation, npm ci installs from the lockfile, never writes to it, and fails if it does not match package.json. Plain install can change the lockfile.

Does a lockfile replace scanning?

No. A lockfile keeps your versions steady. A scan tells you whether those versions have known problems. You want both.

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.