Ten adversarial probes that fire at DRIFT's core privacy invariants — relay blindness, stealth unlinkability, forward secrecy, sealed sender opacity, and more. Each probe spins up the relay in-process and attacks one specific claim. Pass means the claim held under attack. The harness is open source and runs in under 30 seconds.
view the harness →Ten attacks. Zero mercy.
Meet Eve. The harness mints her a real identity, a real client, and full visibility of the relay — then she attacks ten specific claims, one probe each. Pass means the claim held under attack. Exit code 0 means all ten held.
642 lines · in-process FastAPI TestClient — no ports, no network · 10 probes · exit 0 iff all pass · --json · --probe <name>
A real identity in a throwaway vault. Sends every message under attack conditions.
Scans, derives, decrypts. If Bob can't read what Alice sent after the attack, the probe fails loudly.
A real minted identity, not a mock. She reads every relay endpoint, replays tokens, flips bits, and forces duress unlocks.
simulated display — results match actual harness output · run locally to verify
Falsifiable, not just asserted.
Privacy tools that only assert claims are not enough. The Gauntlet makes DRIFT's claims falsifiable — any researcher can run it, add probes, or break it. A failed probe is not hidden; it becomes a bug report. The dashboard shows what a clean run looks like. The script lets you verify it yourself.
read the design doc →The Gauntlet tests protocol-layer invariants in an isolated in-process environment. It does not test your OS, your hardware, your network, or your threat model. A full pass does not mean DRIFT is production-ready — it means the specific claims tested held under automated adversarial conditions. Read the threat model for the full picture.
view threat model →What Eve tried. Why it failed.
tried: scraped every relay endpoint for identity material.
failed because: 4 endpoints expose zero sender or recipient fields — there is nothing stored to scrape.
4 relay endpoints expose zero identity material · 21ms
tried: link ten envelopes to one recipient and derive the next address in the sequence.
failed because: all ten addresses are distinct, and derivation requires the private scan key Eve doesn't have.
10/10 addresses distinct, non-derivable without scan key · 10ms
tried: recover a deleted message key after the ratchet advanced, to decrypt captured ciphertext.
failed because: the key no longer exists anywhere — decryption dies with InvalidTag.
deleted key unrecoverable from advanced chain (InvalidTag) · 0ms
tried: capture a burn request and replay it.
failed because: burn tokens are single-use — the first burn returns 200, the identical replay is rejected with 409.
first burn 200, identical replay 409 · 5ms
tried: read sender identity out of the fields the relay actually stores.
failed because: the stored fields carry no sender identity — the linkable ratchet header is sealed inside the ciphertext.
stored fields ['_id', '_relay_ts', 'addr', 'ct', 'to', 'ts'] carry no sender identity · 3ms
tried: tamper with a published blindness certificate.
failed because: the Ed25519 signature and hash chain reject a single flipped bit — the whole chain fails verification.
4 certs verify clean; tamper rejected · 6ms
tried: bit-flip ciphertext into a forgery and poison the conversation state.
failed because: the AEAD throws InvalidTag, the ratchet survives untouched, and both real messages still decrypt.
InvalidTag on tamper; ratchet survived, both msgs decrypt · 3ms
tried: force a duress unlock and pivot from the decoy to the real keys.
failed because: the duress passphrase yields only the decoy vault — the real keys are structurally unreachable from it.
duress unlock yields decoy; real keys unreachable · 2ms
tried: replay a consumed one-time prekey to run a second handshake as Alice's contact.
failed because: each one-time prekey is handed out and deleted exactly once — the replay is rejected.
OTPK 924191019 consumed once, replay rejected · 22ms
tried: use the relay's delivery hints to spot which messages are real.
failed because: false positives track the dial exactly — at full noise, every message looks like a match and the signal drowns.
rates 0/0.1/1.0 → 0/61/500 of 500 · 4160ms
Where this goes: the Gauntlet is the seed of a "Drift Protocol Compatible" conformance suite — a second implementation that passes all ten probes can legitimately claim interop. It is a test harness, not a bug bounty. Found something it misses? Write the probe that proves it and open an issue.