From 9fc705209d83c77bee425e345a481e45ed622b58 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Thu, 1 Oct 2026 08:19:19 +0200 Subject: [PATCH] outline fixture: read Outline 1.10's __Host-csrfToken cookie (R-744) Outline 1.10 names the CSRF cookie __Host-csrfToken on a secure request and csrfToken over plain HTTP (server/utils/ csrf.ts getCookieName); 1.9.1 always said csrfToken. Proven on 9202 at the live pin 1.10.1: installation.create 302, cookie __Host-csrfToken, apiKeys.create, a published document read back, unknown id and wrong key refused (felhom.eu/documentation/audits/rulings-2026-10-01/D/D2-outline-fixture-9202.txt). The old pattern cannot match that header line (the red: 2026-09-30, both venues). Co-Authored-By: Claude Opus 5.5 (1M context) Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS --- scripts/upgrade_fixtures_box.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/scripts/upgrade_fixtures_box.py b/scripts/upgrade_fixtures_box.py index 1d13e78..c45f9c4 100644 --- a/scripts/upgrade_fixtures_box.py +++ b/scripts/upgrade_fixtures_box.py @@ -1413,12 +1413,16 @@ class Outline: self.tried = f"POST /api/installation.create -> {code}" return None rc, code, out = w.app_curl(sub, "/home", "-D", "-", "-o", "/dev/null", "-H", f"Cookie: {ck}") - csrf = re.search(r"(?im)^set-cookie:\s*csrfToken=([^;\r\n]+)", out or "") + # R-744: Outline 1.10 names the cookie `__Host-csrfToken` on a secure request (server/utils/csrf.ts getCookieName, + # shared/constants.ts CSRF.secureCookieName) and `csrfToken` over plain HTTP — 1.9.1 always said `csrfToken`. + # The double-submit check compares the cookie under the request's own name with the x-csrf-token header. + csrf = re.search(r"(?im)^set-cookie:\s*((?:__Host-)?csrfToken)=([^;\r\n]+)", out or "") if not csrf: - self.tried = "no csrfToken cookie from GET /home" + self.tried = "no csrfToken / __Host-csrfToken cookie from GET /home" return None - cs = csrf.group(1) - rc, code, out = w.app_curl(sub, "/api/apiKeys.create", "-H", f"Cookie: {ck}; csrfToken={cs}", "-H", f"x-csrf-token: {cs}", + cn, cs = csrf.group(1), csrf.group(2) + say(f" outline: CSRF cookie {cn}") + rc, code, out = w.app_curl(sub, "/api/apiKeys.create", "-H", f"Cookie: {ck}; {cn}={cs}", "-H", f"x-csrf-token: {cs}", "-H", "Content-Type: application/json", "-H", f"Origin: {o}", data=json.dumps({"name": "drill"}), method="POST") try: