Skip to content

SRS: three shipped Console HTTP controls have no FR behind them #70

Description

@dichovsky

Group U specifies the Console's loopback bind (FR-U02, docs/design/srs.md:739-741) and its per-run token (FR-U04, srs.md:745-748), but three further controls that src/ui/server.ts implements and that CI exercises have no requirement at any authority level:

  • Host-header allowlist. src/ui/server.ts:630-634 refuses any request whose Host is not exactly 127.0.0.1:<boundPort> or localhost:<boundPort>, with a 403 evaluated before the token check. This is the DNS-rebinding guard — the control that stops a page in the Operator's own browser from driving the port through a hostname the attacker resolves to 127.0.0.1. Loopback binding (FR-U02) does not cover this case.
  • Cache-Control: no-store on every response. respond() (src/ui/server.ts:233), respondMethodNotAllowed() (:242-247), and the SSE stream (:460-463). Relevant because the startup URL carries the token (src/ui/index.ts:112).
  • Constant-time token comparison. tokenEquals (src/ui/server.ts:192-200) uses timingSafeEqual and treats a length mismatch as an ordinary miss rather than an early return. FR-U04 requires the token, not that comparing it leaks no timing.

grep -ni 'host header\|host-header\|rebind\|no-store\|allowlist\|constant.time\|timing.safe' docs/design/srs.md docs/adr/0012-optional-local-ui-server.md returns zero hits, so none of the three is traceable from either the SRS or the governing ADR.

Found while implementing #31 (PR #69), which documents all three in docs/design/security.md. That PR deliberately describes them as implementation controls with no FR-* citation rather than inventing ids, since the routine may not add or renumber requirements — hence this issue.

Impact: each is a load-bearing security control with nothing above it in the authority order. A refactor that dropped the Host check would contradict no requirement, and docs/design/security.md would then describe a guard the code no longer has — the exact drift class docs/README.md's authority order exists to prevent. The traceability appendix cannot grade what it cannot see either: Appendix E's group-U row (srs.md:1377) covers FR-U01FR-U38 and there is no id here to grade.

Note this is a traceability gap, not a vulnerability — all three controls are present, correct, and covered by tests in tests/integration/ui-server.test.ts. Nothing is exposed today.

Acceptance: the SRS gains requirements for the Host allowlist (stating that it is checked before the token and that its purpose is DNS rebinding), for Cache-Control: no-store on every Console response, and for constant-time token comparison — each with a *Verify:* pointer to the test that already covers it. The group-U id-range statements at srs.md:1322 and srs.md:1377 move with them, and docs/design/security.md's ### Console network exposure section is updated to cite the new ids. Whether ADR-0012 should also be amended, or whether the SRS alone suffices, is a judgment call for the implementer — ADR-0012 enumerates the Console's actions, not its transport controls.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentationhelp wantedExtra attention is needed

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions