When your downloads are served from multiple mirrors — whether CDN edge nodes, community mirrors, or geographic replicas — the question of integrity becomes distributed. The origin knows what the correct file looks like, but users downloading from a mirror need a way to verify that what they received matches what the origin published. This is the role of integrity manifests.
This page covers how to design, publish, and maintain integrity manifests for mirrored downloads, using SHA-256 as the hash standard, adding provenance metadata for auditability, and making the verification experience practical for actual users.
Why manifests matter for mirrors
Mirrors can serve corrupted files for several reasons:
- Transfer errors: rsync, HTTP, or FTP transfers that silently corrupt data
- Storage degradation: bit rot on the mirror's storage
- Stale content: a mirror that didn't sync the latest release
- Compromise: an attacker modifying files on a mirror
- Operational error: a mirror operator accidentally overwrites files
An integrity manifest published by the origin and distributed alongside (or separately from) the mirrored files allows users to verify correctness regardless of which mirror they used.
Manifest design
The basic format
A SHA256SUMS file at its simplest:
e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 project-v3.0.0-linux-x64.tar.gz
a948904f2f0f479b8f8564e9a810f8e7e88c51b3c6a7bc9b5f3c4f3b3d7d8a9c project-v3.0.0-darwin-arm64.tar.gz
d7a8fbb307d7809469ca9abcb0082e4f8d5651e46d3cdb762d02d0bf37c9e592 project-v3.0.0-windows-x64.zip
This format is universally supported:
- Linux/macOS:
sha256sum -c SHA256SUMS - Windows PowerShell:
Get-FileHash file.tar.gz -Algorithm SHA256 - Every programming language has SHA-256 libraries
Adding provenance metadata
For richer manifests, include origin metadata:
# MANIFEST.yaml
manifest_version: "1.0"
origin: "https://releases.example.com"
generated: "2026-04-01T10:00:00Z"
generator: "release-pipeline v2.1"
files:
- name: "project-v3.0.0-linux-x64.tar.gz"
sha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
size: 52428800
published: "2026-04-01T09:45:00Z"
- name: "project-v3.0.0-darwin-arm64.tar.gz"
sha256: "a948904f2f0f479b8f8564e9a810f8e7e88c51b3c6a7bc9b5f3c4f3b3d7d8a9c"
size: 48234496
published: "2026-04-01T09:45:00Z"
Provenance fields help with:
- Audit trails: when was this manifest generated, and by what system?
- Freshness checks: is the manifest newer than the files on this mirror?
- Size pre-checks: file size verification before computing the hash (fast failure for truncated downloads)
Signing the manifest
The manifest itself should be signed so users can trust it came from the origin:
# Sign the manifest with Sigstore
cosign sign-blob --output-signature SHA256SUMS.sig \
--output-certificate SHA256SUMS.cert \
SHA256SUMS
# Or with GPG (traditional approach)
gpg --detach-sign --armor SHA256SUMS
A signed manifest is the chain of trust: origin signs the manifest, manifest contains hashes, hashes verify the files.
Distribution strategies
Co-located manifests
Place SHA256SUMS (and its signature) in the same directory as the downloads:
/releases/v3.0.0/
project-v3.0.0-linux-x64.tar.gz
project-v3.0.0-darwin-arm64.tar.gz
project-v3.0.0-windows-x64.zip
SHA256SUMS
SHA256SUMS.sig
Mirrors sync the entire directory, including the manifest. Users download the manifest from the same mirror and verify.
Risk: if the mirror is compromised, the attacker can replace both the files and the manifest. Mitigate by signing the manifest and publishing the signing key or Sigstore identity via a separate channel.
Separate manifest server
Serve manifests from a different infrastructure than the download mirrors:
- Downloads from
mirrors.example.com(geographically distributed) - Manifests from
releases.example.com(single origin, well-secured)
Users download the file from any mirror, then fetch the manifest from the origin to verify.
Advantage: compromising a mirror does not compromise the manifest. Disadvantage: adds a dependency on the manifest server for verification.
DNS-based hash publication
For high-assurance use cases, publish file hashes as DNS TXT records:
_sha256.project-v3.0.0-linux-x64.releases.example.com. TXT "e3b0c44298fc1c..."
DNS records signed with DNSSEC provide a second independent channel for hash verification. This is unusual in practice but used by some security-focused distributions.
Verification UX
The biggest challenge with integrity verification is that most users don't do it. Making verification easier increases adoption.
Command-line verification
Document the exact commands prominently on your download page:
# Download file and manifest
curl -O https://mirror.example.com/releases/v3.0.0/project-v3.0.0-linux-x64.tar.gz
curl -O https://releases.example.com/releases/v3.0.0/SHA256SUMS
# Verify
sha256sum -c SHA256SUMS --ignore-missing
Browser-based verification
For users uncomfortable with the command line, provide a client-side JavaScript hash verifier on your download page. The user selects the downloaded file, and the page computes SHA-256 in the browser (using the Web Crypto API) and compares against the published hash.
This runs entirely client-side — no upload needed.
Package manager integration
If your software is distributed via a package manager (apt, brew, npm), the package manager handles verification automatically using its own manifest and signing infrastructure. Ensure your packages are signed and the manifests are correct.
Common mistakes
Publishing hashes without signatures. An unsigned SHA256SUMS file on a compromised mirror is worthless — the attacker replaces both. Always sign the manifest.
Using HTTP for manifest distribution. Serve manifests over HTTPS only. HTTP allows man-in-the-middle modification of the manifest.
Not including file size in the manifest. Size is a fast pre-check that catches truncated downloads without computing a hash.
Generating manifests manually. Automate manifest generation as part of your release pipeline. Manual processes are error-prone and often forgotten.
Not verifying manifests on the mirror side. Mirror operators should also verify incoming files against the origin manifest. If a transfer corrupts a file, the mirror should detect it before serving it to users.
Verification checklist
- Generate
SHA256SUMSfor all release files - Sign the manifest (Sigstore or GPG)
- Publish manifest and signature alongside downloads
- Verify the published manifest matches local files (self-test)
- Test verification from a different machine using documented commands
- Set up periodic verification on each mirror to detect drift
Related reading on wplus.net
- Fixity at Scale — hashing strategies and corruption detection
- Tamper-Evident Downloads — Sigstore signing for provenance
- Infrastructure hub — hosting and serving fundamentals