Every backup is chained
to the one before it.
If anyone modifies a backup (including your storage provider), DevSafe detects it. The chain breaks, and everything after the tampered snapshot becomes suspect. No trust required.
What it is
Every time DevSafe creates a backup snapshot, it includes a cryptographic commitment to the previous snapshot. This creates a chain. Each link depends on the one before it, all the way back to the first backup.
Think of it like a wax seal on each envelope, where every seal also contains an imprint of the previous seal. If someone opens an envelope and reseals it, the imprint won't match. And because every later envelope references earlier ones, tampering with any single backup invalidates the entire chain from that point forward.
This means your storage provider cannot silently modify, replace, or delete a backup without you knowing. Neither can an attacker who gains access to your storage bucket. Neither can a compromised CI pipeline. The chain catches it.
If snapshot 3 is tampered with, its hash no longer matches what snapshot 4 expects. The chain is broken. DevSafe reports exactly where the break happened.
How it works
DevSafe uses a two-layer verification system built on Merkle trees and nonce-unique AEAD encryption.
Layer 1: Merkle commitment
Each backup snapshot is a git bundle. DevSafe computes a Merkle tree over the bundle contents, producing a single root hash. This hash is a fingerprint of the entire snapshot. Change one byte in the bundle, and the root hash changes completely.
When DevSafe creates the next snapshot, it includes the previous snapshot's Merkle root in its own commitment. This is how the chain forms. Each snapshot carries proof that it knew the exact contents of the previous one.
Layer 2: AEAD authentication
The git bundle is encrypted with nonce-unique AEAD (AES-256-GCM). This provides both confidentiality (no one can read your code) and authentication (no one can modify the ciphertext without detection). The authentication tag is bound to both the encrypted data and the chain commitment.
These two layers are independent. Even if an attacker could somehow forge a valid Merkle root (they cannot, because SHA-256 is collision-resistant), the AEAD authentication tag would still catch the modification. Both layers must pass for a snapshot to be considered valid.
# Each encrypted snapshot contains: snapshot_n = { git_bundle: <encrypted git bundle> merkle_root: SHA-256 over bundle contents prev_commitment: merkle_root of snapshot_(n-1) sequence: monotonic counter (cannot go backward) aead_tag: AES-256-GCM tag (covers all fields) }
The sequence number is monotonic, meaning it only goes up. If DevSafe sees a snapshot with a sequence number lower than or equal to the previous one, it rejects it. This prevents replay attacks where an attacker substitutes an older backup for a newer one.
Verification without trust
The devsafe verify command walks the entire chain from the first snapshot to the latest. It checks every link, every Merkle root, every AEAD tag, and every sequence number. No network calls to DevSafe servers. No trust placed in the storage provider.
$ devsafe verify api-server → checking chain integrity (247 snapshots)… → verifying Merkle roots… → verifying AEAD tags… → checking sequence monotonicity… ✓ chain intact: 247/247 snapshots valid ✓ oldest: 2026-01-15 09:12:03 UTC ✓ newest: 2026-06-30 17:44:21 UTC ✓ no gaps, no replays, no tampering detected
Verification runs entirely on your machine. DevSafe downloads the snapshot headers from your user-owned storage, checks the chain locally, and reports the result. Your storage provider never learns whether you verified or what you found.
If verification fails, DevSafe tells you exactly which snapshot broke the chain and when it was last known good.
$ devsafe verify api-server → checking chain integrity (247 snapshots)… → verifying Merkle roots… ✗ chain break at snapshot 183 (2026-04-02 14:30:11 UTC) prev_commitment does not match snapshot 182 snapshots 183-247 cannot be trusted last known good: snapshot 182 (2026-04-02 11:15:44 UTC)
Running devsafe verify never modifies your backups or your local repos. It is a read-only operation. Run it as often as you want.
Designated-verifier proofs
Sometimes you need to prove your backup chain is intact to someone else. An auditor. A compliance officer. An insurance provider. But you do not want to hand them your encryption key.
DevSafe can export a designated-verifier proof. This is a cryptographic proof that a specific third party can check using only your public key. The proof confirms that your chain is intact and that your backups existed at the claimed times, without revealing the contents of any backup.
$ devsafe verify --export-proof audit-2026-q2.proof \ --verifier auditor@example.com ✓ chain verified (247 snapshots) ✓ proof exported to audit-2026-q2.proof ✓ designated verifier: auditor@example.com # The auditor verifies with: $ devsafe verify --proof audit-2026-q2.proof ✓ proof valid: 247 snapshots, chain intact ✓ signed by: you@devsafe.com ✓ time range: 2026-01-15 to 2026-06-30
The proof is bound to the designated verifier. It cannot be forwarded to a different party and still pass verification. This prevents a proof you gave to one auditor from being reused by someone else without your knowledge.
What the proof reveals
- Chain length (how many snapshots exist)
- Time range (when the first and last snapshots were created)
- Chain integrity (whether any links are broken)
- Your identity (the public key that signed the chain)
What the proof does not reveal
- The contents of any backup
- File names, repository names, or commit messages
- Your encryption key or any key material
- Where your backups are stored
Temporal proofs
Each snapshot in the chain includes a timestamp commitment. This is a cryptographic binding between the snapshot's contents and the time it was created. The commitment is included in the chain, so it inherits all the tamper-evidence properties described above.
Temporal proofs answer one question: did this backup exist at this time?
Because the chain is ordered and monotonic, you can prove that a specific snapshot existed before a certain date. The sequence numbers and timestamps form a timeline that cannot be reordered or backdated without breaking the chain.
$ devsafe verify --at "2026-03-15 12:00" api-server ✓ snapshot 142 existed at 2026-03-15 11:58:33 UTC ✓ chain valid from snapshot 1 through 142 ✓ temporal proof: this backup cannot have been created after 2026-03-15 12:00 UTC
This is useful for regulatory compliance (proving you had backups at a specific point in time), insurance claims (proving data existed before an incident), and intellectual property disputes (proving code existed before a specific date).
DevSafe does not depend on a trusted time server. The ordering guarantee comes from the chain structure itself. Each snapshot must reference the previous one, so the sequence is fixed at creation time. Backdating a snapshot would require re-creating every subsequent snapshot in the chain, which would break the AEAD tags.
Try it yourself
Install DevSafe and run your first chain verification in under two minutes.
$ brew install hxalabs/tap/devsafe # After your first backup completes: $ devsafe verify ✓ chain intact: 1/1 snapshots valid # Every new backup extends the chain. # Run verify again after a few snapshots: $ devsafe verify ✓ chain intact: 14/14 snapshots valid