Tamper-proofing dependencies#
The Buf CLI and the Buf Schema Registry (BSR) use cryptographic digests to detect if a dependency’s content changes between pushes.
If someone tampers with a module upstream, or a compromised network intercepts a download, buf build refuses to use the dependency and fails loudly instead of quietly pulling the altered content into your workspace.
Every BSR commit is content-addressed by a manifest digest.
Every buf.lock entry records that digest.
Every buf build re-verifies it.
As long as buf.lock is checked into source control and you keep the Buf CLI current, your dependencies are protected end to end.
What a tampering attack looks like#
A tampering attack means unauthorized changes reach consumers of a module. Imagine your application depends on a module that defines a message for moving money between accounts. Swapping two field numbers looks almost identical in a code review, but reverses the semantics of every generated client:
message MoveMoney {
- string from_email = 1;
+ string from_email = 2;
- string to_email = 2;
+ string to_email = 1;
google.type.Money amount = 3;
}
Paying someone becomes getting paid. The same shape of attack applies to enum values, field types, and anywhere a small semantic change produces a large behavioral change in generated code. Because Protobuf schemas are often consumed indirectly through generated SDKs, a tampered upstream can fan out to every downstream service without a human ever inspecting the diff.
How the BSR produces digests#
When a module is pushed, the Buf CLI uploads each source file as a content-addressable blob along with a manifest that lists every file in the push and its hash. The BSR stores the blobs and the manifest as content-addressable storage; the resulting commit points at the manifest, which in turn points at every file in the push.
When another module adds that commit as a dependency, the manifest digest is written into buf.lock:
# Generated by buf. DO NOT EDIT.
version: v2
deps:
- name: buf.build/bufbuild/eliza
commit: f3801d450ef94549afec851bc73de581
# Buf CLI watches out for changes in this field
digest: b5:cd74f1dc4de0c750b7cf43df018b368a565de21a748738967c9a630aec95b5f267731a74a1ba142d7dbd2745300976671f9d90aa0a472b1f5b763fd886c66c12
The digest line is what makes tamper detection possible on later builds. Any change to the commit’s content produces a different digest.
How buf build detects tampering#
On every buf build, the Buf CLI populates the local cache with any missing dependencies, then compares each one’s manifest digest against the digest in buf.lock.
If they match, the dependency is safe to use.
If they don’t match, the build fails with a loud warning: the downloaded content differs from what the lock file expects, which could mean a man-in-the-middle attack, a compromised upstream, or a lock-file that wasn’t regenerated after an intentional upstream change.
Either way, the build stops before any code is generated from the altered content.
The fix is always to regenerate buf.lock (buf dep update) after confirming the upstream change is legitimate, which pulls the new digest into source control where your normal code-review process can see it.
Checklist#
- Check
buf.lockinto source control alongsidebuf.yaml. - Keep the Buf CLI up to date so the verification step stays current with the BSR’s digest format.
- Treat
buf.lockdiffs as security-relevant changes in code review, the same way you would a dependency bump in any other package manager.