trustdiff reads untrusted input by design: lockfiles from pull requests, metadata from public registries, configuration files in repositories it audits. A bug that turns any of that into code execution, into a finding that is hidden or reported as a pass, or into a write outside the intended file is a security issue. Please report it privately.
Do not open a public issue for a suspected vulnerability.
- Preferred: GitHub private vulnerability reporting on this repository, at https://github.com/vahapogut/trustdiff/security/advisories/new. The report is visible only to you and the maintainer.
- Fallback: email vahapogut@gmail.com with "trustdiff security" in the subject line. If you want to encrypt the details, send a first message without them and ask for a key.
The maintainer (@vahapogut) is the only person who reads these reports.
- The output of
trustdiff version, or the commit you built from, and your operating system. - The exact command line, the policy file if one was used, and the input that triggers the problem: a package ref, a lockfile, a repository layout, or a recorded registry response. A minimal reproduction in the style of the fixtures under
testdata/is ideal. Never include a real credential or token. - What happened, what should have happened, and the impact you see: code execution, a finding that was hidden or shown as a pass, a file written outside the target, data leaving the machine.
- Whether the problem is already public somewhere.
In scope: anything reachable from the inputs trustdiff processes (registry and advisory responses, lockfiles, manifests, policy files, package manager configuration, git refs given on the command line, the disk cache), and the release pipeline (a way to bypass signing, provenance or checksums, or to tamper with a build dependency).
Out of scope: vulnerabilities in the packages trustdiff reports on (report those to the package or to OSV), and findings trustdiff misses because a registry does not expose the data. Those are ordinary bugs; open an issue. A check that reports a pass for data it never evaluated is in scope.
- Acknowledgement within 3 days of the report.
- For a confirmed issue, a fix or a written mitigation plan with a date within 14 days. Fixes ship as a patch release of the latest minor line, with a GitHub security advisory and a Security entry in
CHANGELOG.md. - Coordinated disclosure: please keep the details private until the fix is released or 90 days have passed, whichever comes first. You are credited in the advisory and the changelog unless you ask not to be.
There is no bug bounty. The project cannot pay for reports; it can thank you and credit you.
During 0.x only the latest minor release line receives security fixes, as a patch release of that line. Earlier minors are not patched; upgrade to the latest release.
| Version | Supported |
|---|---|
| Latest 0.N.x | Yes |
| Earlier 0.x lines | No |
go install github.com/vahapogut/trustdiff/cmd/trustdiff@latest builds the latest tag.
- No telemetry, no auto-update, no analytics, no phone-home of any kind. Normal metadata checks query registry and advisory sources. Optional Cosign verification also retrieves authenticated TUF trust material, and optional GuardDog analysis downloads package sources and metadata.
--offlinedisables network access: local verification requires cached npm metadata and an explicit local trust root; GuardDog is refused before any subprocess starts. - Standard library first. Six third-party modules are allowed (
github.com/spf13/cobra,go.yaml.in/yaml/v3,github.com/BurntSushi/toml,golang.org/x/term,golang.org/x/time,golang.org/x/mod) and CI fails when the direct dependency count exceeds six. CGO is disabled. - Every GitHub Action is pinned to a full 40-character commit SHA. Build provenance comes from GitHub's native attestation action rather than a reusable workflow that must be referenced by tag, so the pin rule has no exception.
- Dependabot watches Go modules and GitHub Actions with a 7 day cooldown, so a version that gets pulled shortly after publication is never proposed here. Dependabot alerts and Dependabot security updates are enabled too, so an advisory published against a dependency this repository already has opens an alert and a pull request.
- CI runs
govulncheck,gosecandgolangci-linton every push and pull request, plus a binary size gate, and runs the test suite under the race detector on Linux as well as without it on Linux, macOS and Windows. - Reproducible builds: goreleaser with
-trimpath,CGO_ENABLED=0,-ldflags=-s -w,-buildvcs=falseandSOURCE_DATE_EPOCHtaken from the commit, so the six archives can be rebuilt and compared byte for byte. The same tag was built twice, hours apart, and all six came out identical. The SPDX documents are not reproducible, andchecksums.txtis not either because it hashes them: every SPDX document carries adocumentNamespacethat has to be unique to that document and acreatedtimestamp, so two runs of syft over the same bytes produce different documents by design. The archive lines insidechecksums.txtdo not change, and cosign signs thechecksums.txta run publishes, so the SPDX documents that run wrote are covered by its signature. The release job installs the exact Go versiongo.modnames in itstoolchaindirective, with nocheck-latest, because a floating patch release would have made the byte for byte claim false the moment a new one shipped: the same tag rebuilt a month later would have been built by a different compiler. The other jobs float forward on purpose, sogovulncheckreads the newest standard library rather than the one this pin freezes. - The signing identity is
release.yml@refs/tags/v*, so whoever can push av*tag can produce a release that verifies. Two repository settings narrow that. A tag ruleset lets only the repository's admin role create av*tag, and the release job runs in areleaseenvironment whose required reviewer has to approve it before anything is built or signed, with admin bypass turned off. They are settings rather than files, sodocs/releasing.mdsection 7 gives the commands that read them back; both were in place when this was last checked, on 2026-09-13. - Releases are built only by the tag-triggered release workflow (
.github/workflows/release.yml).contents: write,id-token: writeandattestations: writeare granted to the release job alone; the workflow default iscontents: read. Artifacts are signed with cosign (keyless, Sigstore, bundle format), attested with GitHub build provenance, listed inchecksums.txtand accompanied by an SPDX SBOM per archive. - Secret scanning and push protection are enabled on the repository.
Every release publishes checksums.txt, its cosign bundle checksums.txt.sigstore.json, one archive per platform (trustdiff_<version>_<os>_<arch>.tar.gz, .zip on Windows) and an SPDX SBOM next to each archive. Download the archive for your platform together with the two checksum files, then run the three steps below from the download directory. Substitute the archive name you downloaded for trustdiff_0.6.0_linux_amd64.tar.gz.
-
Verify the signature on the checksum file. This needs cosign v3 or later. The identity is the release workflow of this repository, running on a version tag.
cosign verify-blob \ --bundle checksums.txt.sigstore.json \ --certificate-identity-regexp '^https://github\.com/vahapogut/trustdiff/\.github/workflows/release\.yml@refs/tags/v' \ --certificate-oidc-issuer https://token.actions.githubusercontent.com \ checksums.txt -
Verify the archive against the signed checksum file.
sha256sum --check --ignore-missing checksums.txt # Linux shasum -a 256 --check --ignore-missing checksums.txt # macOS
On Windows, compare the two outputs by eye:
(Get-FileHash .\trustdiff_0.6.0_windows_amd64.zip -Algorithm SHA256).Hash Select-String windows_amd64 .\checksums.txt
-
Verify the build provenance with the GitHub CLI. This confirms the archive was built by this repository's release workflow from the tagged commit.
gh attestation verify trustdiff_0.6.0_linux_amd64.tar.gz \ --owner vahapogut \ --signer-workflow vahapogut/trustdiff/.github/workflows/release.yml
If any step fails, do not run the binary, and report it through the channels above.