Reproducible Builds and SBOMs

The Trust Gap in Software Builds

Free and open-source software promises transparency, but there is a gap between the source code and the binary that ships to users. Users must trust that the developer's build environment was uncompromised and that the resulting binary actually corresponds to the published source. Reproducible builds close this gap by making it possible for anyone to compile the same source and get a bit-for-bit identical output.

This talk (31c3: Reproducible Builds — Closing the Trust Gap) from Mike (Tor Project) and Seth (EFF) covers the core concepts:

  • Why developers are targets: Build servers and developer machines are high-value attack surfaces. A compromised build server can inject malicious code into software used by millions, with no visible change to the source repository.
  • Reproducible builds as a mitigation: If the same source always produces the same binary, independent parties can verify the build and detect tampering.
  • Real implementations: Tor Browser uses the Gideon system; Debian achieves reproducibility across a significant portion of its package archive; F-Droid runs a verification server for Android packages.
  • The trusting trust problem: Reproducible builds, combined with diverse double-compilation, help address the classic attack where a backdoor is injected into a compiler and propagates through all software it compiles.
  • Remaining challenges: Build environment variations (timestamps, filesystem ordering, locale), ensuring update distribution integrity.

Further Resources

Generating an SBOM in GitHub Actions

A Software Bill of Materials (SBOM) is a machine-readable inventory of all components in your software. GitHub can generate one automatically for your repository, or you can produce one as part of your CI pipeline.

Option 1: GitHub's built-in dependency graph export

GitHub automatically generates a dependency graph for supported ecosystems (npm, pip, Maven, Cargo, etc.). You can export it as an SBOM in SPDX format via the API:

gh api /repos/{owner}/{repo}/dependency-graph/sbom > sbom.json

Or attach it as a release asset from a workflow:

- name: Export GitHub SBOM
  run: |
    gh api /repos/${{ github.repository }}/dependency-graph/sbom > sbom.spdx.json
  env:
    GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Upload SBOM as artifact
  uses: actions/upload-artifact@v4
  with:
    name: sbom
    path: sbom.spdx.json

Option 2: Syft (for deeper analysis)

Syft generates SBOMs from container images, directories, or lock files and supports CycloneDX, SPDX, and other formats:

- name: Install Syft
  uses: anchore/sbom-action/download-syft@v0

- name: Generate SBOM with Syft
  uses: anchore/sbom-action@v0
  with:
    path: .
    format: spdx-json
    output-file: sbom.spdx.json

- name: Upload SBOM
  uses: actions/upload-artifact@v4
  with:
    name: sbom
    path: sbom.spdx.json

What to do with the SBOM

  • Attach it to GitHub Releases so downstream users can audit what went into a release.
  • Feed it into a vulnerability scanner (e.g., Grype, OSV Scanner) to find known CVEs in your dependency tree.
  • Store it as a compliance artifact alongside your release artifacts.

For the security implications of SBOMs and supply chain security more broadly, see the Security and Reproducibility chapter.