Lock files
Last updated: Nov 5, 2026
A lock file records the exact version of each dependency that your project installs. This includes the transitive dependencies, which are the dependencies of your dependencies. Most lock files also record a hash of each package. Most of the package managers that Fluid Attacks supports create a lock file by default. Some package managers do not. This page lists these package managers and the alternatives that Fluid Attacks recommends.
Why a project without a lock file is not safe
A manifest file, for example requirements.txt or pom.xml, usually declares
only the direct dependencies. Many manifests also declare a range of versions,
not one version. Without a lock file, these problems occur:
- Different builds install different versions. The package manager selects the version when it installs the dependencies. When a new version is released, the next build can install it, but the manifest does not change.
- A malicious version can get into your build. Attackers have taken control of maintainer accounts and released malicious versions of popular packages. Without a lock file, the next build can install a malicious version that is in the declared range. A lock file keeps the version that you installed before.
- The package manager does not verify the packages. If a lock file has hashes, the package manager stops the installation when a package is different from the package that you locked.
- The results of the scan are less accurate. Without a lock file, Fluid Attacks analyzes only the direct dependencies that the manifest declares. Fluid Attacks does not find vulnerabilities in transitive dependencies. If a dependency declares a range, Fluid Attacks compares the range with the advisories. Thus, it can report a vulnerability in a version that you do not install. If a dependency does not declare a version, Fluid Attacks cannot analyze it.
Package managers that create a lock file by default
These package managers create a lock file when you install or add dependencies. Add the lock file to your repository. In your CI/CD pipeline, use the command that stops the build when the lock file is not up to date.
| Package manager | Lock file | CI/CD command |
|---|---|---|
| npm | package-lock.json | npm ci |
| Yarn Classic | yarn.lock | yarn install --frozen-lockfile |
| Yarn Berry | yarn.lock | yarn install --immutable |
| pnpm | pnpm-lock.yaml | pnpm install --frozen-lockfile |
| Bun | bun.lock | bun install --frozen-lockfile |
| Poetry | poetry.lock | poetry check --lock |
| Pipenv | Pipfile.lock | pipenv install --deploy |
| uv | uv.lock | uv sync --locked |
| Cargo | Cargo.lock | cargo build --locked |
| mix (Hex) | mix.lock | mix deps.get --check-locked |
| Composer | composer.lock | composer validate, then composer install |
| Bundler | Gemfile.lock, gems.locked | bundle config set frozen true, then bundle install |
| pub | pubspec.lock | dart pub get --enforce-lockfile |
| Swift Package Manager | Package.resolved | swift package resolve --force-resolved-versions |
| CocoaPods | Podfile.lock | pod install --deployment |
Bun 1.2 and later create the text bun.lock file by default. Bun 1.1.39 to
1.1.x create the binary bun.lockb file, unless you use the
--save-text-lockfile option. Fluid Attacks does not read bun.lockb. To
change to the text format, run
bun install --save-text-lockfile --frozen-lockfile --lockfile-only. Then
remove bun.lockb.
Go does not use a lock file. In Go 1.17 and later, go.mod lists all the
modules that the build uses, and the build selects the same versions each
time. Thus, go.mod and go.sum give the same protection as a lock file.
Package managers with an optional lock file
These package managers can create a lock file, but you must turn on this function.
Gradle
Gradle 7.0 and later write the lock state to a gradle.lockfile file in each
project. Gradle 6.4 to 6.9 write this file only if settings.gradle has
enableFeaturePreview("ONE_LOCKFILE_PER_PROJECT"). To turn on dependency
locking, add this block to build.gradle or build.gradle.kts:
dependencyLocking {
lockAllConfigurations()
}Then, create the lock file:
./gradlew dependencies --write-locksThis command locks the configurations of one project only. In a multi-project
build, run it for each project, for example
./gradlew :app:dependencies --write-locks. Keep the default file name,
because Fluid Attacks reads only gradle.lockfile. Gradle stops the build when
the resolved dependencies are different from the lock file.
The Gradle lock file does not have hashes. To verify the packages, also use dependency verification.
NuGet
NuGet creates a packages.lock.json file only for projects that use
PackageReference. To turn on the lock file, add this property to the project
file:
<PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
</PropertyGroup>Then, run dotnet restore. In your CI/CD pipeline, run
dotnet restore --locked-mode. Keep the default file name, because Fluid
Attacks reads only packages.lock.json.
Projects that use packages.config cannot have a lock file. To get a lock
file,
migrate from packages.config to PackageReference.
Package managers without a lock file
These package managers do not have a lock file of their own.
pip
pip does not create a lock file. Fluid Attacks recommends that you change to a package manager that creates a lock file: uv, Poetry or Pipenv.
If you keep pip, write all the dependencies in requirements.txt with exact
versions and hashes. These tools create this file from your direct
dependencies:
pip-compile --generate-hashes requirements.in
uv pip compile --generate-hashes requirements.in -o requirements.txtThen, install with pip install --require-hashes -r requirements.txt. The
resolved versions apply to the Python version and platform that you use to
create the file.
pip 25.1 and later have an experimental pip lock command. This command
creates a pylock.toml file. At this time, Fluid Attacks does not support
pylock.toml, because the function is experimental.
Maven
Maven does not create a lock file. Fluid Attacks recommends that you change to Gradle with dependency locking.
If you keep Maven, declare an exact version for each dependency. Do not use
version ranges, LATEST, RELEASE or SNAPSHOT versions. The
banDynamicVersions
rule of the Maven Enforcer Plugin stops the build when a dependency does not
obey this rule. This method does not give a lock file. Thus, Fluid Attacks
analyzes only the direct dependencies of pom.xml.
The maven-lockfile plugin
creates a lockfile.json file with all the dependencies and their hashes. At
this time, Fluid Attacks does not support this file.
sbt
sbt does not create a lock file, and no plugin gives a reliable alternative. Fluid Attacks recommends that you change to Gradle with the Scala plugin and dependency locking.
Some plugins create lock files for sbt, for example sbt-dependency-lock. At
this time, Fluid Attacks does not support these files.
Search for vulnerabilities in your apps for free with Fluid Attacks' automated security testing! Start your 21-day free trial and discover the benefits of the Essential plan. If you prefer the Advanced plan, which includes the expertise of Fluid Attacks' pentesting team, complete this contact form.