dart pub allows declaring dependencies with version ranges rather than exact versions. When a project is built on a new system, the package manager performs dependency resolution: it queries the package registry and selects a specific version satisfying each declared range, then records the result in a lock file. Committing this lock file to source control ensures that all subsequent builds — on any machine or CI system — use exactly the same resolved versions.

Why is this an issue?

Without a committed lock file, dependency resolution runs anew on every fresh build, always selecting the latest version available that satisfies the declared range. This means different developers and CI systems may silently use different dependency versions, leaving the project exposed if a malicious version of a dependency is published within the allowed range.

Note, if you are authoring a library, an argument can be made to avoid lock files to allow detecting upstream dependency changes that could otherwise silently break your downstream consumers' builds. However, regularly updating your lock file ensures reproducible builds while still giving you visibility into upstream dependency changes.

What is the potential impact?

If an attacker publishes a malicious version of a dependency within your declared version range, an unlocked project may automatically adopt it on the next fresh build. This can result in arbitrary code execution, data exfiltration, or backdoors being silently introduced into your application as part of a supply chain attack.

How to fix it in dart pub

Installing dependencies is safe as long as a valid, up-to-date lock file is present. However, relying on this implicit behaviour means a stale or missing lock file can silently cause the package manager to resolve and download new versions, opening the door to dependency substitution attacks. Using a command that explicitly requires the lock file to exist and be respected makes the expectation clear and prevents accidental updates from slipping in unnoticed.

Code examples

Noncompliant code example

steps:
  - run: dart pub get # Noncompliant

Compliant solution

Use dart pub get --enforce-lockfile to install from the required lock file pubspec.lock. flutter pub get --enforce-lockfile is equivalent for Flutter projects.

steps:
  - run: dart pub get --enforce-lockfile

Resources