From 9ca50d33fd452f584a29e295518a41f696bc3f11 Mon Sep 17 00:00:00 2001 From: Mix Date: Thu, 15 Oct 2026 01:04:45 +0300 Subject: [PATCH] web: Referrer-Policy same-origin; a password shown once emptied on pagehide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit D-B3. Fetch Standard § 3.2 "append a request `Origin` header": under Referrer-Policy no-referrer a request that is not GET/HEAD and not CORS - a form POST, a navigation - gets Origin "null". originAllowed() refuses "null" whenever Sec-Fetch-Site is absent, and Fetch Metadata § 3 sends Sec-Fetch-Site only to a potentially trustworthy URL: every form, sign-in included, failed in Safari before 16.4 and in any browser on a plain-HTTP panel at a name. same-origin nulls Origin only for a request not same origin with its URL and still sends no referrer to another site. The comments of the origin check say so. D-B13. noStore keeps the page out of HTTP caches (RFC 9111 § 5.2.2.5); a history mechanism "might honor" it (§ 6), and Pragma in a response "was never specified" (§ 5.4) - it goes. CopyField.Secret marks the password of out-app-created data-secret, and panel.js empties such fields on pagehide (HTML § 7.5.9, "unload a Document", step 10.2: fired whether or not the document is kept for history traversal). Measured 2026-10-15 in Chrome 152 (the desktop app's browser), a local probe page with Cache-Control: no-store and a data-secret field: Back reloads it (pageshow persisted=false, a new load), so this browser keeps no-store pages out of its back/forward cache; the handler, fired on the same page, empties the field. Firefox and Safari not measured. Tests: the header value; the created page has the password data-secret and the login not, no Pragma. Stand (2026-10-15, make e2e, exit 0): new form_post_with_the_browsers_origin - Referrer-Policy: same-origin on a page; a POST carrying the page's own Origin and no Sec-Fetch-Site, what a browser sends now, passes; one carrying Origin: null, what it sent before, is 403. (A first run failed where the e2e client and a view test scraped the old input markup; both read data-secret now.) go vet and go test ./... pass on the server (24 packages). Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 10 +++++ docs/architecture.md | 2 +- docs/audit-2026-10-12.md | 6 ++- docs/roadmap.md | 2 +- internal/web/handlers/handlers_apps.go | 13 ++++--- .../handlers/handlers_outbound_pages_test.go | 4 +- internal/web/security.go | 23 +++++++---- internal/web/security_test.go | 2 +- internal/web/view/components.go | 4 ++ internal/web/view/outbound_app.go | 2 +- internal/web/view/outbound_test.go | 2 +- internal/web/view/static/panel.js | 16 ++++++++ internal/web/view/templates/components.html | 2 +- test/e2e/health_served_test.go | 39 +++++++++++++++++++ test/e2e/main_test.go | 3 ++ test/e2e/panel_client.go | 2 +- 16 files changed, 109 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce3aab0..c50d29d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -131,6 +131,16 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version copy, names a renewal waiting in the mount, and warns when it has waited longer than the daily check allows; the expiry notice is not sent while a renewal waits on time (assumptions A-65). +- **The panel works in browsers that do not say where a request comes + from.** The panel's `Referrer-Policy: no-referrer` made a browser send a + form's `Origin` as `null`, which the panel refuses unless the browser also + sends `Sec-Fetch-Site`: in Safari before 16.4, or in any browser on a + panel served over plain HTTP at a name, every form - signing in + included - was refused. The policy is now `same-origin`, which still + sends nothing to other sites (assumptions D-B3). +- **A password shown once is emptied when its page is left,** so a browser + that keeps the page for its Back button shows an empty field; the + meaningless `Pragma` header goes (assumptions D-B13). - **Words for what happens to mail match Postfix's.** A message refused with a temporary error while the panel or the spam filter does not answer was called deferred, which in Postfix's words is mail waiting in its queue; diff --git a/docs/architecture.md b/docs/architecture.md index b2a79a8..dc11953 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -776,7 +776,7 @@ are in [plans/panel-redesign.md](plans/panel-redesign.md) § Enforcement. on every response: `Content-Security-Policy: default-src 'self'; object-src 'none'; base-uri 'none'; form-action 'self'; frame-ancestors 'none'`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, -`Referrer-Policy: no-referrer`, and `Strict-Transport-Security` when the cookie +`Referrer-Policy: same-origin`, and `Strict-Transport-Security` when the cookie is `Secure`. Because the policy has no exemptions, no template carries an inline `