fix: two Origin headers state none a policy can answer for
Review of the previous commit. `HeaderMap::get` is first-wins, and the deployment README recommends puts a reverse proxy in front of the socket — one that APPENDS `Origin` rather than setting it leaves two, and answering from the first lets the second be anything at all. No browser sends two, so two is not a state any policy can answer for and the handshake is refused, exactly as an `Origin` that is not text already was. Guarded by two_origins_state_none_this_policy_can_answer_for, proved by restoring the first-wins read, which fails that test alone across the workspace. The test also asserts the allowed origin BY ITSELF is still allowed, so the refusal is demonstrably the second header rather than the first. Second review finding: a_handshake_from_a_foreign_origin_is_refused matched "403" in a Display string, which cannot tell a refused upgrade from a dropped connection. It now matches Error::Http and asserts the status. Proved by changing forbidden() to UNAUTHORIZED, which fails it and a_refusal_is_a_forbidden_response. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FC2jVn8Au7E9JPkw6bwXXH
This commit is contained in:
@@ -293,9 +293,14 @@ the repo's own tests and every scripted client while buying nothing, since an
|
||||
attacker who can run a non-browser client already has direct network access,
|
||||
which is the question `--bind` and a proxy answer. The cost is stated rather
|
||||
than hidden: **a proxy that strips `Origin` turns this check off**, so the
|
||||
proxy's own Origin allow-list stays in the recipe as defence in depth. An
|
||||
`Origin` header that is not valid text is refused rather than read as absent —
|
||||
it is not a value any policy could name.
|
||||
proxy's own Origin allow-list stays in the recipe as defence in depth.
|
||||
|
||||
Two shapes state no origin a policy can answer for, and both are refused rather
|
||||
than read as absent: an `Origin` that is not valid text, and **two `Origin`
|
||||
headers**. `HeaderMap::get` is first-wins, and the deployment this README
|
||||
recommends puts a proxy in front of the socket — one that appends rather than
|
||||
sets the header leaves two, and answering from the first lets the second be
|
||||
anything at all. No browser sends two.
|
||||
|
||||
**What this does not buy is authentication.** It answers "what page is driving
|
||||
this client", never "who is connecting"; anything that is not a browser page
|
||||
|
||||
Reference in New Issue
Block a user