fix(board): refuse foreign Host and Origin on every control-board route (#1507)

After a DNS rebind, a web page could read /api/board and POST /api/reply,
which pastes into a live seat pane. foreignRequest() now runs first and
returns 403 for a non-loopback Host, a wrong port, userinfo or a path in
Host, or any Origin other than http://<Host>. A missing Origin still passes,
which covers the WebUI proxy. Dewey authored it; Rocko approved de9ff942
(review 5a12f08e) with one low wording finding, now fixed in the notes.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-09-26 15:40:34 -05:00
co-authored by Claude Opus 5.5
parent 401cc850bb
commit d1629d610d
8 changed files with 461 additions and 6 deletions
+1 -6
View File
@@ -113,12 +113,6 @@ at every gate. Started 2026-09-12 during the control board MVP.
same path could run a board reply as a slash command. Belongs to CHAT-03I/B3.
No tools/tmux change until that piece. Found by Dewey in the CHAT-02 brief
evidence. (2026-09-26, #1507)
- **Control board checks the bind address but not Host or Origin.** After a
DNS rebind, a web page could read `/api/board` and POST `/api/reply`, which
pastes text into a live seat pane. The WebUI server already checks both.
Not tested against a browser, so the exposure is unproven. Dewey writes the
guard as its own small change before CHAT-02, and Rocko reviews it.
(2026-09-26, #1507, found by Dewey)
## Queue
@@ -130,3 +124,4 @@ Moved to `docs/plans/QUEUE.md` on 2026-09-13. This file holds only gaps.
- Relaunched seat shows the old last message (darkwing, Step 3 log, 2026-09-12): closed by #1512 relaunch activity, af4203ca. Filbert authored it; Darkwing and Dewey reviewed. The live board restart and Gate F remain separate.
- Sage launcher hook uncommitted (2026-09-12): closed by the agents/sage launch files commit, Dewey review R1 revise, R2 approve (`agents/dewey/work/sage-launch-review-2026-09-26.md`), launcher test now covers sage.
- Ledger counts T3 agent messages as human (2026-09-26, #1506): fixed in ef0020ad (Darkwing 6a, Filbert reviewed). `messageKind` now counts a T3 header as agent and the control-board sender as board. It changes no current count, because no source the ledger reads has a T3 header yet. That waits for the T3 thread source (Gate F).
- Control board checked the bind address but not Host or Origin (2026-09-26, #1507, found by Dewey): closed by the board guard commit. `foreignRequest` refuses a non-loopback Host, a wrong port, userinfo or a path in Host, and any foreign Origin on every route. Dewey authored it, and Rocko approved it (`agents/rocko/work/board-guard-review-2026-09-26.md`, 5a12f08e). Rocko's one low finding: URL normalization accepts a root slash, empty userinfo and an empty query in Host, so the notes' wording overstates what the raw-syntax check refuses. No bypass was found.