Files
swaitsandClaude Opus 4.7 7e39781318 Initial release: v0.1.0
Passphrase-based peer rendezvous for iroh-gossip swarms over the public
Mainline DHT. Two nodes that share a passphrase + application salt find
each other and join the same gossip topic — no bootstrap server, no
prior knowledge of peer addresses.

The algorithm is a clock-free variant of HyParView-style partition
healing on BEP 44 mutable items, with K-sharded slots, logical aging
with random-tie eviction, vouching of up to V neighbors at age 1, and
a two-layer AEAD record envelope. Full spec in PROTOCOL.md.

Ships with:

* 119 tests (unit / property / integration / doctest) all green
* 100% mutation-testing catch rate (cargo-mutants)
* cargo-fuzz harnesses for the parse surface
* Kani proofs of no-UB / no-panic on crypto::epoch_of and
  wire::decode_entries across their full symbolic input spaces
* Stateright distributed-system model: safety invariants S1 + S2
  proved exhaustively for N ≤ 6, K ≤ 3; liveness witness under weak
  fairness
* Miri green on the synchronous modules
* cargo-deny + cargo-audit clean
* criterion benches
* Full-matrix CI (Linux + macOS + Windows × stable + MSRV 1.93.0)
* Dedicated nightly lane for Miri / mutation / fuzz / Kani / Stateright

Pinned iroh 0.98.x. License MIT.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-22 22:52:46 -06:00

5.0 KiB

Security Policy

Reporting a vulnerability

Email steve@waits.net with the subject prefix [iroh-gossip-rendezvous security]. Please include:

  • A description of the vulnerability and its impact.
  • Steps to reproduce, ideally with a minimal test case.
  • Your suggestion for a fix or mitigation, if you have one.

I'll acknowledge receipt within 5 business days and aim to publish a fix (or a detailed mitigation advisory) within 30 days. Please do not file a public issue for security vulnerabilities until a fix is available.

Supported versions

Only the latest minor release receives security fixes. Older 0.x lines become unsupported once a newer minor version ships. 1.0 will establish a longer support window.

Threat model

The crate's design assumes:

  • The public Mainline DHT is untrusted: any node can read any slot, publish spoofed records under keys it controls, or drop / replay puts. Signature verification prevents spoofing; last-writer-wins semantics tolerates drop/replay.
  • The passphrase is a shared secret among members. Anyone with the passphrase can participate in the swarm, decrypt DHT records, and sign their own slot writes.
  • The iroh-gossip layer itself provides point-to-point TLS between gossip members. Application payload broadcast over the swarm is visible to every gossip member.

What the crate protects against

  • Passive DHT eavesdroppers: record plaintext (peer IDs, ages) is AEAD-encrypted under a key derived from the passphrase. An observer sees only opaque ciphertext, a public key, and a monotonic sequence number.
  • Active DHT attackers who don't know the passphrase: cannot produce valid signed puts; their malformed records are rejected on read.
  • Cryptographic correctness of the core primitives: HKDF-SHA256 for key derivation, Ed25519 for signing, ChaCha20-Poly1305 for AEAD, all from the audited RustCrypto stack.
  • Per-record key isolation: compromise of a single record's one-time key (k_r) leaks only that record — the wrapper master key W_k stays protected.

What the crate does not protect against

  • Passphrase compromise. The passphrase is the sole secret. Anyone obtaining it can decrypt every past and future DHT record, forge slot writes, and impersonate members. There is no forward secrecy: an adversary who captures DHT traffic and later obtains the passphrase can decrypt the archive.
  • Post-compromise security against a former member. A removed member who still has the passphrase retains full read/write access. Revocation requires an out-of-band passphrase rotation.
  • Metadata confidentiality on the DHT. Observers see: the slot addresses (public, deterministically derived from the passphrase), record sizes, write frequencies, and sequence numbers. These reveal the rough number of active members, the write rate, and the app salt's identity (via slot-address fingerprinting if the adversary guesses app salts).
  • Gossip-layer payload confidentiality. Once the gossip topic is joined, application payloads broadcast over iroh-gossip are visible to every member. Payload encryption is out of scope; layer MLS / RFC 9420 on top if needed.
  • Denial of service on the Mainline DHT. An adversary with heavy DHT resources can crowd out slots or drop puts. The K-sharded design mitigates this (§7 of PROTOCOL.md) but does not eliminate it.

Non-goals

  • MLS / post-compromise security — future work; separate crate if built.
  • Anonymity. Mainline DHT participation is observable; adversaries who correlate DHT queries with network metadata can de-anonymize members.
  • Traffic analysis resistance. Same caveat.

Cryptographic primitives and key derivation

  • Key agreement: None. Keys are deterministically derived from the passphrase + app_salt via HKDF-SHA256.
  • Slot signing: Ed25519 via ed25519-dalek. Each slot has its own signing key, derived via HKDF info string "sk25519:" || be64(slot_k).
  • Wrapper master key: 32 bytes per slot, HKDF info string "wrap:" || be64(slot_k).
  • Per-epoch wrapper: W_k^(e) = HKDF-Expand(W_k, "epoch" || be64(e)) where e = floor(seq / E) (default E = 64). Epoch rotation provides coarse-grained key hygiene but not forward secrecy.
  • Per-record AEAD: a fresh 32-byte one-time key k_r, wrapped under W_k^(e) with a random 12-byte nonce; the record body is AEAD-encrypted under k_r with a fixed all-zero nonce (safe because k_r is one-shot and discarded after encryption).
  • Zeroization: k_r, the derived W_k^(e), and any intermediate HKDF buffers containing passphrase bytes are zeroized after use.

Supply chain

  • All crypto dependencies are from the RustCrypto organization.
  • CI runs cargo deny check and cargo audit on every push; known transitive unmaintained advisories are documented in deny.toml.
  • cargo-semver-checks guards public API stability on PRs.