docs(security): #9/#13 fixed, S7 rationale corrected (red-team follow-up)
17/18 now fixed. A red-team of the three accepted findings showed #9 and #13 rested on a circular premise (each was the other's "safe fallback") and S7's written rationale was wrong (signing exercises the same modexp Marvin targets). #9/#13 closed; S7 accept retained for the corrected reasons + amplifier hardened. See f0574a5, f6c9576. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,21 +30,23 @@ remedy, are deferred/accepted with a reason.
|
|||||||
| #6 | Med | **FIXED** (`3532e35`) — EIS relay moved to `$XDG_RUNTIME_DIR` (0700) + symlink reject |
|
| #6 | Med | **FIXED** (`3532e35`) — EIS relay moved to `$XDG_RUNTIME_DIR` (0700) + symlink reject |
|
||||||
| #7 | Med→Low | **FIXED** (`3532e35`) — `vdisplay::ENV_LOCK` serializes setup-path env mutation (data-race UB closed); full per-session `SessionContext` threading for value-confusion is a follow-up |
|
| #7 | Med→Low | **FIXED** (`3532e35`) — `vdisplay::ENV_LOCK` serializes setup-path env mutation (data-race UB closed); full per-session `SessionContext` threading for value-confusion is a follow-up |
|
||||||
| #8 | Low | **FIXED** (`6f903f7`, *Win CI/box pending*) — web-password file created empty → locked → written |
|
| #8 | Low | **FIXED** (`6f903f7`, *Win CI/box pending*) — web-password file created empty → locked → written |
|
||||||
| #9 | Low | **ACCEPTED** — disarm-on-any-attempt IS the documented single-online-guess (prior-fix #2); the delegated-approval flow is structurally immune. Steer hostile LANs to it |
|
| #9 | Low | **FIXED** (`f0574a5`) — a red-team showed the original "delegated approval is the immune fallback" premise was circular with #13. Added a **fingerprint-bound PIN window** (`arm_for`/`pin_for_attempt`): an attempt from any other fingerprint is rejected WITHOUT consuming the window, so an unpaired peer can't pair *or* burn a window armed for a specific device. (Disarm-on-attempt still gives the single-online-guess for the unbound flow; with #13 now flood-resistant, the knock fallback genuinely holds. Web "pair-this-pending-device-with-a-PIN" UX is a follow-up.) |
|
||||||
| #10 | Low | **FIXED** (`3532e35`) — ENet decrypt-failed warn throttled (exponential) |
|
| #10 | Low | **FIXED** (`3532e35`) — ENet decrypt-failed warn throttled (exponential) |
|
||||||
| #11 | Low | **FIXED** (`6f903f7`, *Win CI/box pending*) — logs dir DACL-locked (subsumed by #3) |
|
| #11 | Low | **FIXED** (`6f903f7`, *Win CI/box pending*) — logs dir DACL-locked (subsumed by #3) |
|
||||||
| #12 | Low/Info | **FIXED** (`3532e35`) — parked pairing-waiter cap (+regression test) |
|
| #12 | Low/Info | **FIXED** (`3532e35`) — parked pairing-waiter cap (+regression test) |
|
||||||
| #13 | Info | **ACCEPTED** — `PENDING_CAP` + LRU + `requested_at` refresh make an actively-retrying device non-evictable |
|
| #13 | Info→Low | **FIXED** (`f0574a5`) — the "actively-retrying device is non-evictable" claim was really a timing race (and the designed flow parks, doesn't re-knock). Added a **per-source-IP cap** (`MAX_PENDING_PER_IP`, QUIC-validated source) so one host can't fill/evict the queue, and eviction now **never drops a live parked knock** — making the delegated-approval path genuinely flood-resistant |
|
||||||
| S2 | Low–Med | **FIXED** (`3532e35`) — a malformed Opus frame drops the frame, keeps the shared mic open |
|
| S2 | Low–Med | **FIXED** (`3532e35`) — a malformed Opus frame drops the frame, keeps the shared mic open |
|
||||||
| S3 | Low | **FIXED** (`3532e35`) — held buttons/keys are capped `HashSet`s |
|
| S3 | Low | **FIXED** (`3532e35`) — held buttons/keys are capped `HashSet`s |
|
||||||
| S4 | Low | **FIXED** (`3532e35`) — Epic launcher-cache reads size-capped |
|
| S4 | Low | **FIXED** (`3532e35`) — Epic launcher-cache reads size-capped |
|
||||||
| S5 | Low→Info | **FIXED** (`3532e35`) — `fps==0`/absurd rejected at the `open_video` chokepoint |
|
| S5 | Low→Info | **FIXED** (`3532e35`) — `fps==0`/absurd rejected at the `open_video` chokepoint |
|
||||||
| S6 | Low→Info | **FIXED** (`3532e35`) — shared mic mpsc bounded (drop-newest) |
|
| S6 | Low→Info | **FIXED** (`3532e35`) — shared mic mpsc bounded (drop-newest) |
|
||||||
| S7 | Low→Info | **ACKNOWLEDGED** — `rsa 0.9` Marvin has no fixed upstream release; GameStream is off by default and this is a signing (not decryption-oracle) path. Migrate the GameStream identity to Ed25519/ECDSA when feasible |
|
| S7 | Low→Info | **ACCEPTED, rationale corrected + hardened** (`f6c9576`) — the prior "signing, not decryption, so the path isn't exercised" reason was *wrong* (signing runs the same secret-exponent modexp Marvin is about). Accept stands for the right reasons: no decryption/padding oracle; the signed `serversecret` is host-random (not attacker-chosen); signing is operator-PIN-gated; GameStream is off by default and the native plane uses rustls not `rsa`; Moonlight mandates RSA-2048 (no Ed25519 migration possible). Also closed the timing-sample amplifier: sign once per ceremony. No upstream `rsa` fix exists |
|
||||||
|
|
||||||
**Net:** 15 of 18 fixed — 5 Linux-verified clusters, 4 Windows DACL paths (#2/#3/#8/#11, awaiting CI),
|
**Net:** 17 of 18 fixed — 5 Linux-verified clusters, 4 Windows DACL paths (#2/#3/#8/#11, awaiting CI
|
||||||
and #5 (now on-box validated on the RTX box, 2026-06-29); #9/#13 accepted-with-rationale; S7
|
compile-confirm), #5 (on-box validated on the RTX box, 2026-06-29), and #9/#13 (closed after a
|
||||||
acknowledged (no upstream fix). No finding remains open and actionable.
|
red-team showed their accepts were circular). S7's accept stands but its rationale was corrected and
|
||||||
|
the timing amplifier hardened; only the transitive `rsa 0.9` advisory itself is un-fixable (no
|
||||||
|
upstream release). No finding remains open and actionable.
|
||||||
|
|
||||||
## Consolidated overview & top priorities
|
## Consolidated overview & top priorities
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user