Do not point a generic scanner at the repository and hope. Bazel's MODULE.bazel.lock records module resolution, not a language level package list. Build the inventory from the language specific lockfiles or pinned files your rules use, then scan those, and use the Bazel lockfile to prove reproducibility.
What MODULE.bazel.lock holds
The Bazel documentation says the lockfile sits at the workspace root and stores the results of module resolution and module extension evaluation. It records hashes of remote registry files used in resolution, any yanked versions chosen, and for each module extension its inputs and outputs. Its stated purposes are reproducible builds, faster incremental resolution and protection against unexpected dependency updates.
It only includes dependencies used in the current build invocation, and the docs recommend running the tidy command regularly to keep it current.
That makes it an input to reproducibility, not a bill of materials. Many third party language libraries come in through extensions or separate pinned files that your rules read.
Lockfile modes
The lockfile mode flag has four values, according to the docs.
| Mode | Behaviour |
|---|---|
| update (default) | Uses the lockfile and adds missing information |
| refresh | Like update, but refreshes mutable information about hourly |
| error | Fails if information is missing or outdated, no changes or network during resolution |
| off | Lockfile neither checked nor updated |
For CI, error mode is a good choice. It fails the build when the lockfile is stale, so the scan input matches what you build. Extensions marked reproducible may still use the network, as the docs note.
Building a scannable inventory
- List the module dependencies from your MODULE.bazel file.
- Find each language ruleset and its pinned file, such as a Maven pin file, a Python requirements lock or a Go sum file.
- Scan those files with a normal dependency scanner.
- Map each result to the Bazel targets that use it, so owners can act.
Step four is the hard one in practice. Check Bazel's query documentation for how to list the targets that depend on an external repository, and use that to route findings.
Pitfalls
- A scan of source folders misses everything Bazel downloads.
- A scan of the output directory can mix build tools and test dependencies with shipped ones.
- Hermetic builds are reproducible, not necessarily vulnerability free. See Bazel hermetic builds for what hermeticity does and does not give you.
Run it per deliverable
Pick the targets that you ship, and scope the inventory to those, so tools and tests do not pollute results.
Safeguard scans dependencies from manifests and lockfiles and generates SBOMs. The free scan at https://gold.safeguard.sh/scan accepts a project so you can see the output for one pinned file.
Quick check
Is MODULE.bazel.lock a package list?
No. It records module resolution and extension results, with hashes of registry files.
Which lockfile mode fails on a stale lockfile?
Error mode, which fails if needed information is missing or outdated.
Sources
Last reviewed: 19 October 2026.