reviews/current/objective-20260909T223027Z/qwen__qwen3-coder-next.md
On this page

Independent Pi/OpenRouter review: qwen/qwen3-coder-next

Source: a10323dede4413fbf295916b8ad12e3dbad7514e. Status: completed.

Security Review: Timelock Proxy v2 (RandomX Delayed-Release Design)

Executive Summary

This implementation delivers confidentiality with delayed disclosure of encrypted records using a novel construction of parallel RandomX puzzles combined with timestamp-bound epoch management. Under the explicit assumptions that:

  1. RandomX is computationally hard to shortcut,
  2. AWS/Nitro attestation is authentic,
  3. The public puzzle/time-bound are observed, and
  4. No practical side-channel/compile-time compromise exists,

the service successfully prevents intermediaries from accessing request/response contents until the puzzle is solved.

However, critical evidence gaps exist preventing a complete safety guarantee. The most severe issues relate to:

Below is a detailed breakdown of verified guarantees, critical gaps, and known risks.


A. Adversary Capability A: Can request/response contents be recovered early?

SUPPORTED CONDITIONALLY: Contents remain encrypted from intermediaries and host if puzzle isn't solved and epoch is still active.

Evidence in favor (supporting confidentiality):

  1. Strong encryption primitives used correctly:

    • v2_proxy.rs:105 uses XChaCha20Poly1305 with a fresh 24-byte nonce for each record
    • relay-timelock/src/lib.rs:92-124: Record key derivation uses HKDF-SHA256 with unique context including puzzle ID
    • Records are sealed inside a hierarchical structure: age encryption (to operator's public key) wrapped inside tlock_age (locked to future drand round)
  2. Inner TLS relays upstream GETs:

    • v2_proxy.rs:161-200: The enclave establishes TLS with upstream servers itself, never exposing the destination to the parent
    • dns.rs:182-211: DNS-over-HTTPS resolution happens inside the enclave
    • net.rs:96-154: ECH (Encrypted Client Hello) is attempted when available, hiding SNI
  3. Ciphertext never leaves the enclave unencrypted:

    • v2_proxy.rs:104-119: Plaintext record is canonicalized to CBOR inside the enclave, then encrypted before any network I/O
    • The host daemon (crates/host/src/main.rs) only receives and stores encrypted ciphertext via the vsock interface
  4. Configuration-bound retention:

    • crates/common/src/lib.rs:32: Minimum lock time is 7 days (604800 seconds)
    • config/relay-v2.toml:7: Epoch duration is 86400 seconds (24 hours)

Critical gaps limiting confidence:

  1. Missing puzzle publication deadline enforcement:

    • v2_epoch.rs:144: The activate function publishes the puzzle after generation completes, but there is no cryptographic proof that the puzzle was published before the epoch activation deadline
    • Attack scenario: A malicious parent/attacker with the ability to delay or suppress the publish operation could cause:
      • A puzzle that was already solvable at generation time to become a new epoch's puzzle after its activation deadline
      • A situation where the puzzle was published with less than the required delay remaining

    Root cause: While publication_not_before (line 110) prevents publishing too early, there is no mechanism ensuring that puzzles are published before their activation deadline. The code structure assumes parent honesty about artifact persistence timing.

    Impact: This could allow an attacker to trivially "solve" future puzzles by replaying or reusing previously computed work.

  2. Active key exposure window before puzzle publication:

    • v2_epoch.rs:171-177: The signer key is generated at boot
    • v2_epoch.rs:94-96: The Epoch struct holds the key (epoch key) in Zeroizing<[u8;32]>
    • Missing protection: The epoch key exists in memory from generation until publication, during which time a host compromise could read it directly from process memory

    The current model relies on:

    • Zeroizing (line 8) to clear the key when dropped, but this doesn't prevent:
      • Memory snapshots taken while the key is alive
      • Side-channel extraction (DRAM remapping, cache attacks)
      • Compiler/library bugs that copy the secret to non-zeroizing storage

    Impact: If an attacker obtains the epoch key before puzzle publication, they can decrypt any record encrypted with that key, even before the RandomX puzzle is solved.

  3. No cryptographic binding between records and puzzles:

    • relay-timelock/src/lib.rs:233-235: SignedManifest::id() only includes the puzzle + service key + signature
    • v2_proxy.rs:117-118: The headers x-attested-relay-puzzle and x-attested-relay-evidence point to artifacts, but these are HTTP headers that can be stripped or replaced
    • Missing feature: There is no cryptographic binding in the encrypted record itself that ties it to a specific puzzle/manifest ID that can only be verified after puzzle publication

    This is explicitly noted as a limitation in the threat model:

    "Individual record envelopes are not service-signed. Once the epoch key is public, anyone holding it can create another valid AEAD record."

    Impact: A malicious archive could replay old puzzles with new records, or mix up records from different epochs. Provenance relies on external records (e.g., Cloudflare logs) rather than cryptographic proof.

  4. Puzzle signature binding is insufficient:

    • crates/timelock/src/lib.rs:216-226: SignedManifest::verify() checks the service signature
    • However, the puzzle itself is only signed once at generation time, and the signature doesn't include a timestamp or epoch activation deadline

    Missing feature: A puzzle signature should be invalid if published after a certain time relative to epoch activation.


B. Adversary Capability B: Can epoch keys/secrets be obtained early or make work reused prematurely?

VIOLATED: Missing protections against work sharing and key exposure

Critical violations:

  1. No protection against shared/precomputed RandomX work:

    • crates/timelock/src/lib.rs:287-398: The generate function uses 7 parallel RandomX segments
    • The segments are chained: seed_{i+1} = unwrap(segment_i) where the final segment yields the epoch key
    • Missing feature: There is no mechanism to ensure that work done on one puzzle cannot be reused for another

    Attack scenario: If an attacker can influence the epoch selection (e.g., by controlling the parent's clock), they could:

    • Generate a puzzle with epoch=0 (or a low epoch number) and precompute segments 1-6
    • When epoch=1 is later requested, only solve segment 7

    While the threat model acknowledges this isn't a proven VDF, the construction doesn't enforce sequentiality across epochs or prevent partial reuse.

  2. Epoch key exposure window:

    • v2_epoch.rs:94: key: Zeroizing<[u8;32]> (the epoch key) is held in the Epoch struct
    • v2_epoch.rs:104-151: The run function holds the Epoch in memory for the entire epoch lifetime
    • v2_epoch.rs:47-52: The expire_active function only erases the epoch when its monotonic time expires, not its NSM timestamp

    Attack scenario: A parent/host compromise that happens during the epoch lifetime can:

    • Read the epoch key from memory (even if zeroized on drop, it may exist in copies)
    • Use this key to decrypt any record encrypted with that epoch key
    • Publish the key before the puzzle is solved, breaking confidentiality
  3. Checkpoint mechanism has no cryptographic verification:

    • crates/timelock/src/lib.rs:404-456: The Checkpoint struct includes a digest but:
      • The digest is only validated against the checkpoint itself, not against the epoch key commitment
      • There is no proof that intermediate segment values are correct until the final key is recovered

    Missing feature: Checkpoints should be signed by the enclave or include a cryptographic proof that the work was done correctly.

  4. Generation and solving share the sameRandomX implementation:

    • crates/timelock/src/lib.rs:458-498: The solve function uses the same code path as generation
    • Missing feature: There is no distinction between "generation work" and "solving work" that would prevent:
      • Reusing a generation cache for solving
      • Parallelizing generation across multiple epochs to speed up future solving

C. Supporting Evidence: Where the design is strong

Strong design decisions:

  1. Zeroizing secrets:

    • zeroize::Zeroizing is used consistently for keys and intermediate values
    • relay-timelock/src/lib.rs:171-173: The signing seed is zeroized immediately after use
  2. Bounded resource usage:

    • crates/enclave/src/v2_proxy.rs:78-80: Requests are bounded by a semaphore
    • crates/enclave/src/v2_proxy.rs:107: Record publishing has a 30-second timeout
  3. Content-addressed storage:

    • crates/enclave/src/v2_epoch.rs:59: Artifacts are named by their SHA256 digest
    • crates/host/src/artifacts.rs:67-123: The host daemon only stores artifacts that match their digest, preventing tampering
  4. Hardware verification:

    • crates/enclave/src/hardware.rs:237-267: Graviton5 verification uses NSM, CPU ID, and EC2 API attestation
  5. DNS resolution in enclave:

    • dns.rs:182-211: Resolves names over HTTPS, never exposing queries to the parent

D. Critical Missing Evidence: What prevents confidence

Missing verification:

  1. No proof that puzzles were published within their validity window:

    • Requirement: A puzzle should only be valid if published before epoch_activated + max_publish_delay
    • Missing: No timestamp in the puzzle manifest, no signature covering the publish deadline

    Evidence: relay-timelock/src/lib.rs:388-397: The puzzle is signed before it's published, with no binding to a publish deadline.

  2. No cryptographic binding between puzzle and attestation:

    • Requirement: The puzzle should only be valid if the attestation is fresh and for the same enclave
    • Missing: The puzzle signature doesn't include the attestation timestamp or PCR values

    Evidence: v2_epoch.rs:88: The puzzle artifact is published after the attestation, with no cryptographic link.

  3. No durability proof for ciphertext storage:

    • Requirement: Records should only be returned to clients if they are durably stored
    • Missing: The parent's "OK" acknowledgment is not cryptographically signed or tied to durability

    Evidence: crates/host/src/main.rs:339-348: The host writes "OK\n" after storing, but this doesn't prove replication, persistence, or prevention of deletion.

  4. No proof of key erasure:

    • Requirement: Epoch keys should be irrevocably erased after expiration
    • Missing: No hardware or OS-level guarantee that all copies are erased

    Evidence: The design relies on Zeroizing, which is good practice but not provably complete.


E. Concrete Attack Vectors

Attack 1: Puzzle publication deadline bypass

** Attacker capability**: Parent/host with ability to delay publish operations ** Trigger**: Delay publish for a solvable puzzle until after its epoch activation deadline ** Result**: Puzzle becomes valid for a future epoch without additional work ** Evidence**: v2_epoch.rs:144 has no deadline enforcement for puzzle publication

Attack 2: Epoch key extraction

** Attacker capability**: Host compromise during epoch lifetime ** Trigger**: Read memory of the enclave process ** Result**: Epoch key is available before puzzle is solved ** Evidence**: v2_epoch.rs:94 holds key: Zeroizing<[u8;32]> in memory until expiration

Attack 3: Puzzle replay with old attestation

** Attacker capability**: Malicious archive with old puzzles and attestations ** Trigger**: Replay old puzzle with new record ** Result**: Archive can serve old puzzles as if they were new ** Evidence**: No cryptographic binding between puzzle and attestation timestamp

Attack 4: Work sharing across epochs

** Attacker capability**: Attacker can influence epoch selection ** Trigger**: Precompute work for low epochs, use for higher epochs ** Result**: Reduces effective security of the puzzle ** Evidence**: RandomX segments are not tied to specific epochs in a way that prevents reuse


F. Recommendations

High priority:

  1. Add puzzle publication deadline:

    • Include a published_before timestamp in the puzzle manifest
    • Sign this timestamp as part of the puzzle signature
    • Enforce that published_before <= epoch_activated + max_publish_delay
  2. Cryptographically bind puzzle to attestation:

    • Include the attestation timestamp/PCR values in the puzzle signature
    • Require the attestation to be fresh (e.g., within 1 hour) for puzzle validity
  3. Verify puzzle publication timing:

    • Add a published_at timestamp that is cryptographically bound to the puzzle
    • Verify this timestamp is within the epoch's validity window
  4. Improve key erasure:

    • Use hardware-level key erasure if available (e.g., Nitro Enclave Key Management)
    • Add a "key destroyed" attestation to prove erasure

Medium priority:

  1. Add record puzzle binding:

    • Include the puzzle ID in the encrypted record's nonce or context
    • Require puzzle publication before allowing record decryption
  2. Add durability proof:

    • Have the parent sign a durability attestation for each record
    • Include this in the record's cryptographic binding
  3. Prevent work sharing:

    • Tie RandomX segments to specific epochs in a way that prevents reuse
    • Add a "work committed" attestation before allowing puzzle publication

Low priority:

  1. Add checksums for intermediate values:

    • Include checksums for each RandomX segment during generation
    • Verify these checksums during solving
  2. Add work proof:

    • Include a Merkle tree root of all segment hashes
    • Require this root to be published with the puzzle

G. Final Assessment

Confidentiality guarantee: CONDITIONALLY SUPPORTED with major caveats.

The design successfully prevents intermediaries from accessing request/response contents if:

However, the following gaps prevent a strong safety guarantee:

  1. Missing puzzle publication deadline enforcement (VIOLATED)
  2. Active epoch key exposure before publication (VIOLATED)
  3. No cryptographic binding between records and puzzles (VIOLATED)
  4. No durability proof for ciphertext storage (VIOLATED)

Would I rely on this for sensitive content? NO, not until the above gaps are addressed.

Recommendation: Do not deploy for sensitive data until:

  1. Puzzle publication deadlines are enforced,
  2. Epoch keys are protected until after puzzle publication, and
  3. Cryptographic binding between records, puzzles, and attestations is implemented.

The design shows promise but is not yet production-ready for high-security applications.