carlos / platform Public

spec: login POST routes by next; a login POST to an ungated route is 404

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 2f0e570940bf66b55e6dcd54aed0c22f39fe1888 parent d595c1f
1 file changed, +22 −4
  • docs/superpowers/specs/2026-09-07-password-gate-design.md +22 −4
diff --git a/docs/superpowers/specs/2026-09-07-password-gate-design.md b/docs/superpowers/specs/2026-09-07-password-gate-design.md
index 5e2743681..3b62df343 100644
--- a/docs/superpowers/specs/2026-09-07-password-gate-design.md
+++ b/docs/superpowers/specs/2026-09-07-password-gate-design.md
@@ -159,10 +159,28 @@ redirect after a successful POST, or the too-many-attempts page.
### 4.2 The reserved path
`POST /.carlos/gate` on a gated host is the login form's action. Fields:
-`password`, `next`. On any other host or method the path is ordinary and
-reaches the app. `next` is accepted only if it starts with a single `/`
-(not `//`, not a scheme), else it becomes `/`; that is the entire
-open-redirect surface and it is closed at the door.
+`password`, `next`. `next` is accepted only if it starts with a single `/`
+(not `//`, not a scheme, no control bytes), else it becomes `/`; that is
+the entire open-redirect surface and it is closed at the door.
+
+**The edge routes a login POST by `next`, not by its own path** (review
+finding, 2026-09-07). A hostname that routes by path prefix resolves each
+request's first segment to a target route; `/.carlos/gate` has no such
+segment and would fall through to the front host's own route — so a gated
+prefix target could never be logged into, and the password would be
+proxied to whatever app fronts the hostname. So, for exactly `POST
+/.carlos/gate`, the edge parses the form (bounded, 4 KiB) and resolves the
+upstream against the path in `next`, which is the path the visitor was
+refused on. On a host with no prefix map this resolves to the same route
+the request path would have; on a prefix host it resolves to the target
+the visitor was trying to reach, whose hash judges the password and whose
+host signs the cookie (§4.3).
+
+**A login POST to an ungated route is a 404, never proxied.** The page is
+only ever rendered by a gated route, so a POST that reaches an ungated one
+is a stray or a probe; forwarding a form field named `password` to an app
+that never asked for it is the one outcome to rule out. On every other
+method the path is ordinary and reaches the app.
Outcomes: