reviews/current/objective-20260909T224107Z/moonshotai__kimi-k3.md
On this page

Independent Pi/OpenRouter review: moonshotai/kimi-k3

Source: a10323dede4413fbf295916b8ad12e3dbad7514e. Status: completed.

Independent Security Review: timelock-proxy v2 (attested-relay-enclave)

Source reviewed: frozen runtime at a10323dede4413fbf295916b8ad12e3dbad7514e, v2 reachability via crates/enclave/src/v2_main.rs (bin target attested-relay-enclave, sole ENTRYPOINT in build/Dockerfile.graviton5 lines 32–35). The legacy tlproxy-enclave binary is built into /out but is not copied into the EIF stage. Documentation/CI material was treated as claims, not evidence.

Method note: I have no execution environment; every test in the tree is unexecuted by me and treated as a claim, not evidence.

Missing source that limits this review: the full vendor/randomx/ tree (only randomx.h and the build hash-checker were provided), config/enclave.toml, crates/enclave/src/main.rs (legacy), crates/cli/, the parent-side port-8005 credential bridge, and measurements/. Where these matter, I say so explicitly.


Verdicts

Property Verdict
A. Pre-delay confidentiality of request/response contents (URL path+query, response body/headers) from in-scope adversaries SUPPORTED CONDITIONALLY
A. Confidentiality of destination identity (hostname/IP) VIOLATED by design (acknowledged in threatmodel §6; must not be confused with contents)
B. Early recovery of epoch keys/seeds/intermediates; pre-solved-puzzle injection SUPPORTED CONDITIONALLY (no injection path found; rests entirely on Nitro memory isolation + NSM entropy + measured code)
B. Delay magnitude "≈ one week" SUPPORTED CONDITIONALLY — publication-relative (≈6–7 days), reference-hardware-calibrated, explicitly not hardware-independent
B. Fail-closed behavior under delayed/replayed/withheld host messages SUPPORTED CONDITIONALLY (availability only; a malicious parent can always halt service)
Side-channel / microarchitectural resistance INSUFFICIENT EVIDENCE
FFI/native correctness of the vendored RandomX fork (RANDOMX_FLAG_V2) INSUFFICIENT EVIDENCE
Post-release record provenance / archive completeness LIMITED (acknowledged): records are not individually signed; host ACK ≠ durability
Dependency supply-chain hygiene (rustls/aws-lc-rs/hyper/hickory/etc. at locked versions) INSUFFICIENT EVIDENCE (not audited here)

A. Can an in-scope adversary recover or infer contents before the intended delay?

Analysis of the content path, byte by byte:

  1. Client → enclave. The Python client (client.py:126–180) performs inner TLS 1.3 (ssl.MemoryBIO, minimum_version = TLSv1_3, CERT_NONE + check_hostname=False) and authenticates only via verify_document (verify.py:131–142): fresh 32-byte nonce, ±5-minute timestamp, AWS-root chain validity, exact nonzero pinned PCR0, public_key == SPKI of the actual TLS peer on that connection (verify.py:110–114), policy checks including state == "ready" for live use (verify.py:126). No application data precedes verification — the only pre-verification payload is the nonce GET. Relay.get() auto-verifies if the stream is absent and never reuses a broken stream (client.py:167–180). This binding chain is the strongest part of the design: relaying a valid attestation cannot authenticate an attacker's TLS endpoint, because the document binds the connection's SPKI.

  2. Outer transport. Inner TLS bytes are base64'd into GET query parameters (transport.py:122–174; host http_relay.rs:166–219). Cloudflare/host see ciphertext plus sizes/timing. The stop-and-wait session protocol with exact-replay caching (http_relay.rs:89–163) handles adversarial reorder/replay/truncation without duplicating inner bytes; conflicting retries fail closed. Session hijack by other clients requires the 128-bit reqid; the in-scope transport parties who can see reqid can disrupt but not decrypt.

  3. Enclave handling. GET-only, bodyless requests (v2_proxy.rs:54–58); target validation against SSRF/credential/port tricks (v2_proxy.rs:127–137), rechecked after DNS resolution per address (net.rs:129–131, 240–251) and on every redirect hop (v2_proxy.rs:161–199). No client headers are forwarded upstream; upstream responses are capped at 10 MiB total including redirect history. The sealed record is built (canonical CBOR), encrypted (v2_proxy.rs:104–105), published and ACK-gated before the response is returned (v2_proxy.rs:107–119). Errors never echo request-derived content to clients or logs (static messages only; v2_diagnostics.rs, v2_main.rs:128–132).

  4. Upstream TLS terminates in the enclave with WebPKI roots (net.rs:56–71); parent carries ciphertext.

Findings on A:

Verdict A: SUPPORTED CONDITIONALLY — conditioned on (i) the client actually executing the full verification path with an independently pinned PCR0, (ii) Nitro/NSM trust, (iii) ordinary primitive strength, and (iv) B below (epoch-key secrecy until solve). Metadata exceptions: destination identity, sizes, timing — real, but not concealing a contents-inference path I could find.


B. Early key/puzzle-capability recovery without breaking RandomX

Working through the enumerated vectors:

Findings on B:

Verdict B: SUPPORTED CONDITIONALLY for no-early-key/no-pre-solved-puzzle, with the explicit conditions: Nitro memory isolation, NSM entropy quality, measured-code correctness (this review covers the Rust; the RandomX fork is not covered), and the calibration assumption that a reference sequential solver is ≈506 hashes/s on Graviton5-class hardware. The delay is publication-relative: records sealed near epoch end get ≈6 days, not 7 (acknowledged §6). An adversary with faster sequential RandomX throughput shortens recovery proportionally — this is expressly outside the assumed guarantee.


Strongest code-grounded reasons attacks are blocked

  1. Attestation binds policy + connection SPKI + fresh nonce; clients pin PCR0 and reject non-ready or mismatched states (verify.py:52–142; attest.rs:140–168; v2_main.rs:94–114).
  2. Secrets come only from NSM, fail-closed, all drawn before expensive work; kernel reseed precedes TLS/keygen (attest.rs:43–82, 197–214; v2_main.rs:150–155; lib.rs:312–325).
  3. Activation is anchored before first disclosure; delayed ACKs shrink/kill rather than rebase; rotation fails closed (v2_epoch.rs:76–150).
  4. Records are sealed and ACK-published before response delivery; every admitted request (including failed upstream fetches) yields a record attempt (v2_proxy.rs:85–119).
  5. The 7-segment serial composition has no cross-segment shortcut: AEAD-chained wraps + commitment + strict Ed25519 with canonical encoding (lib.rs:174–236, 458–498; archive.py:97–158).
  6. Host store is content-addressed, digest-verified, never-overwrite (artifacts.rs:67–123); public serving re-verifies hashes (artifacts.rs:208–233).
  7. Bounded resources at every adversary-controlled input (sessions, pending, frames, headers, bodies, connections, permits).

Unresolved questions / requested source

  1. Full vendor/randomx source + SHA256SUMS + the RANDOMX_FLAG_V2 fork diff (highest priority — the delay primitive itself).
  2. config/enclave.toml, crates/enclave/src/main.rs, crates/cli/ (completeness/reachability confirmation).
  3. The parent-side port-8005 credential bridge implementation (hardware.rs:130–147 connects to it; it is not in the frozen tree).
  4. measurements/graviton5-calibration-* and evidence for any completed full-duration production generation/rollover/recovery (docs claim these remain unverified).
  5. Deployment facts: nitro-cli invocation (debug mode off, CPU/memory), outer Cloudflare config.
  6. Whether serde_cbor Value map ordering is actually RFC 7049 canonical (test unexecuted).
  7. Dependency-advisory status of the locked tree (not audited).

Would I rely on this for sensitive content under the explicit assumptions?

Conditionally, for contents only: the Rust-side construction is careful, consistently fail-closed, and I found no pre-delay contents-inference path. I would not rely on it to hide which sites are contacted (resolver + parent + IP exposure is structural). I would treat the one-week delay as a ≈6–7-day, publication-relative, hardware-speed-calibrated estimate — not a proven lower bound — and I would not place high-value reliance on the delay until the custom RandomX fork is audited and at least one full-duration production epoch rollover and independent recovery has been observed. The docs themselves state these remain unverified.