Independent Pi/OpenRouter review: moonshotai/kimi-k2.7-code
Source: a10323dede4413fbf295916b8ad12e3dbad7514e. Status: completed.
Independent assessment
Scope: frozen source commit a10323dede4413fbf295916b8ad12e3dbad7514e, enclave binary attested-relay-enclave (v2_main.rs reachability), with documentation at 85c61e96590b52ded80a995ef5d1e379b2287761 treated as a claim. Tests and CI attestations were not executed and are not treated as proof.
High-level verdicts
| Property | Verdict |
|---|---|
| A. Confidentiality of request/response contents from intermediaries/operator before the intended ~1-week delay | SUPPORTED CONDITIONALLY – the cryptographic composition blocks direct plaintext disclosure if the RandomX primitive, Nitro isolation, NSM time, and the client verification path hold. Metadata (sizes, timing, SNI when ECH fails, status codes, artifact names) is visible; memory/side-channel hygiene is not proved. |
| B. Early recovery of epoch keys/private seeds/intermediates or equivalent decryption capability without breaking RandomX | SUPPORTED CONDITIONALLY / NO DEMONSTRATED VIOLATION – I found no code path that releases an epoch key, an unreleased seed, or a usable shortcut before the intended serial work. The main caveats are (1) the next epoch key already exists in enclave memory during the current epoch, (2) no evidence is provided that RandomX cache/VM memory is securely scrubbed, and (3) no per-record signatures exist, so post-release provenance is weak but that does not enable pre-release decryption. |
The design does not provide per-request delay: the lock time starts at puzzle publication, so records created late in an epoch have less remaining delay than records created early. This is acknowledged in the threat model (threatmodel.md) and is not treated as a confidentiality violation, but it is a real limitation on the advertised “approximately one week” property.
A. Confidentiality of request/response contents
What blocks content recovery
-
Records are encrypted under the hidden epoch key before leaving the enclave.
crates/timelock/src/lib.rs:81-90derivesrecord_keyfromepoch_keyvia HKDF-SHA256 keyed by the manifest id.crates/timelock/src/lib.rs:92-124encrypts with XChaCha20Poly1305 using a 24-byte random nonce and an AAD that bindsversion || epoch || sequence || manifest_id.crates/enclave/src/v2_proxy.rs:104-107waits for the sealed JSON to be published before returning the upstream response.- The only thing published is the ciphertext hex string (
EncryptedRecord), plus a SHA256-named artifact file on the untrusted host.
-
The epoch key is not in any public artifact.
- The published manifest (
crates/timelock/src/lib.rs:28-41) contains onlykey_commitment = SHA256(epoch_key), plus the public wrapped keys andseed_1. solve()incrates/timelock/src/lib.rs:458-498recomputes the chain and checks the commitment; only the correctepoch_keypasses.- Attestation policy (
crates/enclave/src/v2_main.rs:55-71) advertises the service signing key and work parameters, but never the epoch key or seeds.
- The published manifest (
-
The enclave does not serve application traffic until a fresh attestation binds the exact code, hardware policy, and inner-TLS peer.
crates/enclave/src/v2_main.rs:94-114requires a 32-byte nonce and includes the enclave TLS SPKI in the NSM document.python/attested-relay/src/attested_relay/verify.py:131-146checks the nonce, timestamp freshness, PCR0, Graviton5 readiness, andpublic_key == peer SPKI.python/attested-relay/src/attested_relay/client.py:143-165performs this verification before any request is sent and refuses dev mode unless explicitly allowed on loopback.
-
Upstream destinations are resolved and validated inside the enclave.
crates/enclave/src/dns.rsresolves over DoH by IP; the parent sees only encrypted DNS traffic.crates/enclave/src/v2_proxy.rs:127-137andcrates/enclave/src/net.rs:240-251reject private/loopback IPs, non-443 ports, credentials, fragments, and redirects to disallowed hosts.- WireGuard mode (
crates/enclave/src/wg.rs) hides upstream IPs from the parent entirely.
Concrete execution trace for A
Attacker: parent host / network observer with access to all host-held artifacts and all bytes on the outer relay.
- The outer request is
GET /relay?reqid=...&payload=<inner TLS ciphertext>(crates/host/src/http_relay.rs:166-219). The payload is opaque TLS 1.3 ciphertext. - Even if the attacker replays or modifies outer chunks, the inner TLS session is authenticated between the client and the enclave; the outer host cannot decrypt it.
- After the enclave fetches the upstream page, it builds a JSON/CBOR record containing the URL, headers, and body, then immediately encrypts it (
crates/enclave/src/v2_proxy.rs:98-107). The host receives only...record.jsonciphertext. - The host may delete or replace that file, but
crates/host/src/artifacts.rs:67-123only accepts exact content-addressed names and refuses to overwrite differing content. Replacing it with a different ciphertext still does not reveal plaintext. - Decryption requires the epoch key, which requires solving the published puzzle.
Limitations / what is not protected
- Metadata: the host sees connection counts, outer-payload sizes, response sizes, status codes,
x-attested-relay-record/puzzle/evidenceartifact names, and timing. If ECH is unavailable or falls back, the parent/SNI observer can see the destination host (crates/enclave/src/net.rs:189-193, fallback to plain TLS inconnect_tls_once). This is accepted leakage per the threat model. - The upstream itself learns both request and response by design.
B. Early epoch-key / seed / equivalent-decryption recovery
What I looked for
The review specifically examined: generation vs solving parallelism, shared work, publication ordering, host acknowledgements, time handling, restart, expiration, request leases, key reuse, checkpoints, attestations, and active/chosen-input attacks.
Findings supporting the no-early-recovery claim
-
No shortcut in the wrapping chain.
- Each segment is
y = RandomX^{iterations}(seed_i), thenseed_{i+1}(orepoch_key) is encrypted with a key derived fromy(crates/timelock/src/lib.rs:246-284). - The published
wrapped_keysreveal only ChaCha20-Poly1305 ciphertext; the wrapping key isHKDF-SHA256(y, context). Under the RandomX assumption,ycannot be predicted without doing the work.
- Each segment is
-
No cross-epoch or cross-segment shared work.
- Fresh
dataset_key, seven seeds, andepoch_keyare drawn from NSM randomness for every epoch (crates/timelock/src/lib.rs:301-325). - The dataset is keyed by
dataset_key, so each epoch requires fresh dataset setup (crates/timelock/src/randomx.rs:49-72). seed_1is public, butseed_2..7are wrapped and never exposed until their segment is solved.
- Fresh
-
Delayed/replayed host acknowledgements cannot extend or rebase an epoch.
crates/enclave/src/v2_epoch.rs:76-102recordsactivated_at_msandexpires_at_msbefore waiting for the puzzle publication ACK. A late ACK cannot shift the wall-clock expiry.- If the ACK is delayed beyond
expires_at_ms,active.accepts(now)fails and the epoch is discarded (crates/enclave/src/v2_epoch.rs:98). - The integration test
tests/test_v2_e2e.py:345-361demonstrates this: a 6-second ACK delay with a 5-second epoch leaves the service inwarmingand returns 503 without serving the request.
-
Expired epochs reject new work strongly, and in-flight work keeps a bounded lease.
crates/enclave/src/v2_epoch.rs:40-52watchdog erases the active state whenmonotonic_expired()is true.crates/enclave/src/v2_proxy.rs:82-84clones the currentArc<Epoch>before releasing the read lock; admitted requests keep the key alive until sealing finishes.crates/enclave/src/v2_epoch.rs:153-211tests that the key is dropped after the last request lease is gone.
-
No host-provided epoch parameters or puzzles.
crates/enclave/src/v2_main.rs:160-168verifies Graviton5 hardware, NSM PCR4 parent binding, and EC2 instance identity before production service starts.crates/enclave/src/v2_epoch.rs:104-151always generates the next puzzle inside the enclave usingrelay_timelock::generate_with_rngwith NSM randomness; the parent cannot inject a manifest, seed, or epoch key.- On restart,
v2_main.rs:169-172andv2_epoch.rs:105derive fresh signing material and a fresh random epoch counter; there is no persistence of old keys to reuse.
-
Checkpoints cannot smuggle progress.
crates/timelock/src/lib.rs:434-455validates manifest id, segment/iteration bounds, and a SHA256 checksum over the checkpoint fields.crates/timelock/src/lib.rs:476-487overwrites the resumedxonly at segment boundaries via the authenticated AEAD unwrap; a wrongxsimply fails with “segment authentication failed” inunwrap()(crates/timelock/src/lib.rs:262-284).- Unit tests in
crates/timelock/src/lib.rs:638-661verify tampered checkpoints are rejected.
-
Attestations prevent relaying and replay.
- The client supplies a 32_byte nonce; the NSM signs it (
crates/enclave/src/attest.rs:136-168). - The NSM document binds the exact inner-TLS SPKI (
crates/enclave/src/tls.rs:27-34,v2_main.rs:107), so relaying another enclave’s valid attestation to a different TLS endpoint is rejected by the Python verifier (verify.py:113-114).
- The client supplies a 32_byte nonce; the NSM signs it (
What weakens the no-early-recovery claim
-
The next epoch key is generated during the current epoch and remains in enclave memory until activation.
crates/enclave/src/v2_epoch.rs:104-151computesgenerated = generate_with_rng(...)at the moment the current epoch becomes active, then waits (potentially another ~day) before publishing/activating it.GeneratedPuzzlecontains the fullepoch_key(crates/timelock/src/lib.rs:49-52). This secret therefore lives inside the enclave for the entire lifetime of the previous epoch, not just its own.- Under the AWS trust model this is not accessible to the operator; however, it is a real increase in exposure window and a target for any side-channel or memory-extraction capability.
-
No evidence that RandomX cache/VM memory is securely scrubbed.
crates/timelock/src/randomx.rs:39-118wraps raw C pointers.Dropcallsrandomx_release_*, butRANDOMX_FLAG_SECURE(used atrandomx.rs:59) only enforces W^X for JIT pages; it is not documented to zero scratchpad/dataset memory.- The Rust
Zeroizingwrapper scrubs the high-levelepoch_keyand seeds on drop, but it does not reach the C++ allocator/VM state. After a VM is dropped and the allocator reuses the page, the internal chain values may remain physically present. - Mitigation: under AWS Nitro the enclave memory is not directly readable by the parent, but this remains an unverified assumption, exactly the kind the prompt flags as not assumed safe.
-
No per-record provenance signature.
- The record is secured only by AEAD (
crates/timelock/src/lib.rs:92-124). Once the epoch key is public, anyone can construct a valid-looking record. - This does not allow an adversary to read records early, but it means the archive cannot prove that a record was produced by this enclave rather than forged after thefact. The threat model (
threatmodel.md) already lists per-record origin signatures as a missing gap.
- The record is secured only by AEAD (
-
Approximate delay is from puzzle publication, not from each request.
- Daily epochs (
config/relay-v2.toml:7) mean a request made just before the epoch expires is decryptable roughly one day sooner (on average) than a request made at epoch start. - This is explicitly accepted by the owner but is a real deviation from a uniform per-request delay.
- Daily epochs (
Minimal reproduction/test sketches
- Normal decryption path: build
relay-timelock, callsolveon a published puzzle, thendecrypt-record; the integration testtests/test_v2_e2e.py:256-343already does this. I did not run it. - Tampered record / wrong key: modify one byte of
record.ciphertextorrecord.nonce;decrypt_recordreturns “record authentication failed” (crates/timelock/src/lib.rs:145-155). Unit tests atcrates/timelock/src/lib.rs:630-637cover variant tampering. - Checkpoint smuggling: create a mid-segment checkpoint with a wrong
xbut a valid SHA256 checksum and pass it tosolve(..., Some(wrong), ...); it fails inunwrap()or at the final commitment check (crates/timelock/src/lib.rs:493-497). Tests atcrates/timelock/src/lib.rs:649-661cover this. - Delayed ACK rebasement: reproduce the protocol in
tests/test_v2_e2e.py:345-361or instrument the host record sink to sleep acknowledgement; the epoch fails to activate and the service stays closed. - Memory scrubbing: inspect
/vendor/randomximplementation for explicitcalloc/memsetof VM scratchpads and dataset pages; compare withDataset::create_vm/Drop. I could not do this because the full C++ source was not included in the snapshot.
Strongest reasons attacks are blocked
- The epoch key is the only decryption capability; it is derived only by serial RandomX work, protected only by a public SHA256 commitment, and never stored in or transmitted through any host-facing artifact.
- Record encryption is authenticated with a modern AEAD, fresh random nonces, and context that binds epoch/sequence/manifest id, so neither the host nor a later solver can undetectably alter a pre-release record.
- Epoch lifetimes are bounded by signed NSM time plus monotonic clock, and new epochs are generated independently from NSM randomness, so the host cannot replay, roll back, or rebase an epoch to re-use an old, partially solved puzzle.
- Client verification binds the TLS peer to the exact measured code/hardware policy with a Fresh nonce before any sensitive request, preventing attestation replay and man-in-the-middle on the inner TLS channel.
Missing evidence that limits the conclusion
- Full
vendor/randomxC++ source was not in the snapshot; I reviewed only the header. Without it I cannot say whether the VM/cache/dataset memory is cleared, whether flags are honored correctly, or whether there are side-channel concerns in the implementation. - Dynamic/runtime evidence that
Zeroizingactually reaches all temporary copies placed byserde_json,serde_cbor,hex, and the RandomX C++ allocator, and that pages are not swapped/paged out to host-controlled storage. - A completed production run of full-duration generation, rollover, and offline key recovery. The documentation states this is unverified.
- Side-channel / cache-analysis study of the enclave’s use of RandomX and Rust TLS on the Graviton5 platform within the Nitro hypervisor.
- Per-record origin signatures or an equivalent public append-only log, which would strengthen post-release provenance but are not required for pre-release confidentiality.
Requested additional source
Please provide the complete **vendor/randomx/** C++ implementation (not just the header) for the pinned commit, so the memory-handling and flag behavior of the FFI layer can be reviewed. If a formal or experimental timing/noise analysis of the enclave’s RandomX usage exists, that would also reduce the conditional part of the verdicts.
Bottom line
I would not unconditionally rely on this for highly sensitive content, because the confidentiality guarantee is conditional on (a) the unproven RandomX serial-work assumption, (b) the unverified memory/side-channel behavior of the RandomX FFI and enclave runtime, and (c) the operational assumption that the service remains running long enough rotate epochs and publish puzzles. within the explicit assumptions stated by the owner—AWS and standard primitives are trusted, RandomX has no shortcut, and no side-channel extraction is available—the design appears to prevent in-scope adversaries from recovering request/response contents or epoch keys dramatically earlier than the intended serial solving delay. There is no code-backed violation of early key recovery, but the evidence is conditional, not comprehensive.