reviews/current/objective-20260909T223027Z/meta__muse-spark-1.3.md
On this page

Independent Pi/OpenRouter review: meta/muse-spark-1.3

Source: a10323dede4413fbf295916b8ad12e3dbad7514e. Status: completed.

Independent defensive review — a10323dede4413fbf295916b8ad12e3dbad7514e v2_main.rs reachability only. No execution; all tests cited NOT EXECUTED.

Verdicts

A. Early recovery/inference of request/response CONTENTS — SUPPORTED CONDITIONALLY

No practical pre-delay plaintext/key recovery without breaking RandomX found in frozen code, iff:

This is not proof of impossibility.

B. Early epoch-key/seed capability or forced use of substantially-solved puzzle without breaking RandomX — SUPPORTED CONDITIONALLY

Generation/solving asymmetry, publication gating, monotonic expiry, bounded leases, sequence exhaustion, content-addressing and fail-closed paths block the obvious in-scope vectors in code, iff same trusts plus enclave-memory isolation and correct FFI/kernel/RNG/Instant behaviour, which were not proved.

No VIOLATED for practical early key/plaintext recovery. Availability/retention/provenance gaps below are real limits, separated from content-confidentiality.

Cross-cutting — INSUFFICIENT EVIDENCE

Hardware-independent timing, absence of microarchitectural side-channels, complete memory erasure, native/kernel/library correctness, full-duration production generation/rollover/recovery. threatmodel.md §7 itself states warming only, ~25.14h generation vs 24h epoch, unverified full run, S3 without Object Lock/retention verification, Cloudflare/third-provider pending. These limit reliance.

Traces checked

Request/response bytes

python/.../client.py:42-123 InnerTLS over transport.py:122-174 exchange/send (/relay?reqid&seq&ack&payload&send, stop-and-wait, identical-retry) -> crates/host/src/http_relay.rs:89-163 Session::exchange, 221-264 handle, 271-321 serve (opaque, bounded MAX_CHUNK 4096, MAX_PENDING 256K, MAX_OUTPUT 32K) -> crates/host/src/main.rs:181-206 forwarder (TCP:443 -> vsock 8443) -> crates/enclave/src/v2_main.rs:184-197 TlsAcceptor + http1 -> crates/enclave/src/v2_proxy.rs:42-120 handle/dispatch:

Upstream: v2_proxy.rs:139-200 connect_upstream/fetch -> net.rs:96-154 connect_tls (in-enclave resolve, cert vs host, ECH retry-once, public_destination bail) -> dns.rs:89-211 resolve/query (DoH by IP to 1.1.1.1/8.8.8.8 from v2_main.rs:157, TLS to IP, MAX_DNS_MESSAGE_BYTES 65535) -> relay.rs:85-110 Net::connect_ip (Upstream refuses direct when relay-required/down) -> transport.rs:135-141 connect_ip(CONNECT ip:port) only IPs to parent; parent main.rs:231-281 handle_tunnel/connect_upstream carries bytes; caller always TLS over it. Redirects re-validated, 5 max, 64K headers/trailers, max_response_bytes 10M (v2_proxy.rs:175,186,182).

Record plaintext (v2_proxy.rs:98-103 version 3 + exchanges with url/method/status/headers/trailers/response_body_b64/complete) -> timelock/src/lib.rs:73-91 record_context/record_key (HKDF from epoch_key, puzzle.id, AAD epoch/sequence/puzzle-id) -> 92-124 encrypt_record(XChaCha20Poly1305, 24B OsRng nonce) -> 125-156 decrypt_record (version/epoch/puzzle-id, commitment, AEAD).

Publication: v2_epoch.rs:57-74 publish (sha256(data).suffix, 32M bound, 3 tries, OK\n required) -> transport.rs:169-176 connect_records(vsock 8001) -> host/main.rs:307-350 records_server/handle_record -> host/artifacts.rs:67-123 store (content-address check, create_new, idempotent exact-match only, sync_all+dir sync) -> 188-233 verified_file/serve (hash re-verified on read, immutable cache).

Keys

Strongest code-grounded blocks (why easy attacks fail)

  1. Inner-TLS MITM by operator/front replaying чужой attestation: verify.py:110-128 _bound_policy requires doc.public_key==SPKI(peer_der) (client.py:60,161-163), protocol_version 2, randomx 2.0.1/aaafe71.../v2/7, iterations 1..1e12, graviton5_verified, ready (live), plus 52-107 _authenticated_document PCR0 pin (non-zero 48B), ES384 COSE, AWS-root 641a03..., chain validity at signed time, ±5min freshness, 32B nonce match (131-138). client.py:143-165 establishes new session/nonce per verify(), no app data before. Repro sketch (NOT EXECUTED): MITM proxy with valid stolen doc but different SPKI -> _bound_policy raises attested TLS key differs.
  2. Unrecorded upstream interaction on sequence exhaustion: v2_proxy.rs:87,122-125 reserves fetch_update checked_add before fetch; u64::MAX fails closed, never wraps/reuses AAD sequence.
  3. Delayed ACK rebasing expired puzzle as fresh: v2_epoch.rs:82-83 anchors monotonic before puzzle disclosure; 97-98 accepts(now) after bundle; 144 timeout(60s, activate) + 145 publication_not_before=expiration + 132-140 wait. Host stall >60s -> run returns, warming; stall <60s but past expiry -> ensure fails. Matches tests/test_v2_e2e.py:345-361 (NOT EXECUTED).
  4. Expired key lingering via global ref: 40-52 watchdog monotonic-only clear; tests 178-210 prove Arc release except bounded request lease (v2_proxy.rs:82,89-107 lease ≤ ~30s fetch +30s publish). Repro (NOT EXECUTED): expire active, assert weak.upgrade().is_none() after dropping lease.
  5. Silent weak-entropy fallback: timelock/lib.rs:312-325 + tests 580-602 require all 16 fills (dataset_key+7 seeds+epoch_key+7 nonces); attest.rs:43-62,197-214 zeroizes on failure, no OS fallback in prod; v2_main.rs:150-152 abort if seed_os_rng fails.
  6. Forged puzzle/checkpoint/record: timelock/lib.rs:174-236 canonical_bytes/id/verify (deny_unknown_fields, fixed-width signed bytes, verify_strict), 400-456 Checkpoint::validate (manifest-id, bounds, digest, seed_1 at 0,0), 493-496 commitment; archive.py:119-154 verify_bundle pins PCR0, binds puzzle-params to attested policy, manifest_id=sha256(canonical+key+sig), _strict_signature small-order/noncanonical reject. Tamper tests in lib.rs:612-681 (NOT EXECUTED).
  7. Parent content read of records/puzzles: only dataset_key/seed_1/wrapped_keys/commitment + EncryptedRecord{nonce,ciphertext} cross vsock/disk (framing.rs, artifacts.rs); record_key HKDF + XChaCha AAD binds epoch/sequence/puzzle-id. Host store/serve hash-checks.
  8. Diagnostics/error oracle: v2_diagnostics.rs:33-41 static printable ≤160B, drop-on-full, 200ms IO timeout; v2_main.rs:123-131 maps all run errors to static string; v2_proxy.rs:46-50 maps dispatch failures to 502 relay operation failed; transport.rs:16-39 bounded parent lines.

Findings requiring conditional acceptance (not counted as content-recovery violations but must be explicit)

F1. Deliberate metadata enables candidate inference. Parent/front sees outbound IP, SNI unless ECH accepted (net.rs:94-95,150), DoH resolver sees questions, sizes/timing visible through inner-TLS + /relay chunking (transport.py:122-174, http_relay.rs). Threat model §6 accepts. Impact: hostname/size/timing inference, not full plaintext. Do not describe as hostname-hiding/anonymity.

F2. Publication-relative ~7d, not per-request 7d. config/relay-v2.toml:6-7 iterations 43768124/epoch 86400; 7 serial segments ≈7d on reference, generation 7-parallel ≈25h. Last record in 24h epoch has ~1d less remaining. Threat model §6 accepts. Impact: late-epoch records decrypt sooner after capture.

F3. Post-release forgery. threatmodel.md §5: record envelopes not service-signed; after solve anyone with epoch key can mint valid AEAD. Provenance needs prior trusted digest/receipt/publication, not implemented. Impact: provenance, not pre-delay confidentiality.

F4. Durability not proved by ACK. v2_epoch.rs:54-56 comment + threatmodel.md §5: malicious OK\n is ordering only; kill-after-upstream-before-seal loses interaction (GET side-effects possible); S3 without Object Lock, no enclave-authenticated retention check, Cloudflare/third-provider pending (§7). Impact: availability/retention/completeness.

F5. Live verifier as shipped does not enforce quantitative work policy. verify.py:121-124 checks 1<=iterations<=1e12, not ≈43M; no epoch_seconds check. Security relies on exact PCR0 pin covering relay-v2.toml + SEGMENTS/RANDOMX_* (verify.py:118-120, archive.py:143-147). If deployer accepts operator-supplied PCR0 or allow_dev, low-work image passes range check. Attacker: malicious operator + lax pin. Repro (NOT EXECUTED): build iterations=8 image, verify with its own PCR0 -> verified True; with prod PCR0 -> PCR0 mismatch. Must pin independently and gate ready+graviton5_verified.

F6. Generation > epoch causes fail-closed gaps. relay-v2.toml:3-4 ~25.14h vs 24h; v2_epoch.rs:126-128 return on generation failure. Impact: warming/503 gaps (v2_proxy.rs:82-83), no reuse of old key — safe but unavailable.

Unresolved / INSUFFICIENT EVIDENCE (need explicit assumption or more source)

U1. Side-channels/timing. No W^X/JIT note aside from randomx.rs:59 flags|128|16; RandomX data-dependent memory access, shared instance CPU, Instant/kernel clock, allocator copies of input/x, Dataset/VM buffers not zeroized (only app keys Zeroizing). Speculation alone is not a confirmed vuln — request: cache/timing analysis, Nitro memory-encryption/scheduling docs, disclosure of solver-hardware advantage measurements. U2. FFI/composition/kernel. randomx.rs:48-82 unsafe Sync sharing, unchecked init_cache/init_dataset void returns, Vm::hash raw pointers; attest.rs:216-270 raw ioctl constants for pinned 4.14.256, reseed_kernel tick reasoning; build.rs hash-pins source but does not prove integration. Request: vendor/randomx/SHA256SUMS, kernel version evidence, graviton5-calibration raw logs, full-run generation/rollover/recovery logs. U3. NSM time parsing trusts local device without signature check in-enclave (attest.rs:289-295 parses payload only). Justified only if /dev/nsm path is AWS-isolated from parent — accepted under “AWS trusted” but parent-host vs hypervisor boundary should be documented; replay of stale trusted_time_ms cache avoided on v2 path by using uncached, but confirm no legacy caller reintroduces cached time for admission. U4. Host is_public weaker than enclave public_destination (host/main.rs:283-302 allows multicast/>=240/198.18/15/192.0, all-V6 filtered differently vs enclave/net.rs:240-251 deny-all-V6 + extra V4 denies). Currently defence-in-depth only because enclave filters before sending IP; confirm no direct host-tunnel caller bypasses enclave check. Request: host invocation args, Cloudflare worker, S3 uploader, solver fleet code if relied for delay/retention claims.

Would I rely for sensitive content?

Under explicit assumptions (AWS trusted, exact independent PCR0, correct live verifier use, tolerance of metadata + publication-relative ~6–7d + public-after-solve + no durability/provenance guarantee + fail-closed gaps), for low-to-moderate sensitivity GETs where hostname/size/timing leakage is acceptable: cautious conditional use. For highly sensitive content requiring strict per-request ≥7d, hostname hiding, guaranteed retention, or post-release authenticity: no — gaps F1–F6/U1–U4 preclude it.