From 63e5a89f979e2bf7c526a88193e762ab5e4853d4 Mon Sep 17 00:00:00 2001 From: mm-kevcenteno Date: Tue, 28 Jul 2026 10:15:27 -0400 Subject: [PATCH 1/3] Remove deprecated headers and stale policy features Feature-Policy was superseded by Permissions-Policy. X-XSS-Protection is non-standard, deprecated, and can itself introduce XSS vulnerabilities in otherwise safe pages; our Content-Security-Policy covers what it was for. Also drop the Permissions-Policy features that no browser recognizes, verified against Chrome 149 and 150: ambient-light-sensor, battery, document-domain, execution-while-not-rendered, execution-while-out-of-viewport, and speaker-selection. Chrome reported each of these as an unrecognized feature, so they never had any effect. --- bin/_headers.config.ts | 28 +++++----------------------- 1 file changed, 5 insertions(+), 23 deletions(-) diff --git a/bin/_headers.config.ts b/bin/_headers.config.ts index a08cf8fb8..b383d2c80 100644 --- a/bin/_headers.config.ts +++ b/bin/_headers.config.ts @@ -120,33 +120,17 @@ const config: HeadersConfig = { 'https://www.gstatic.com', ], }, - 'Feature-Policy': [ - "accelerometer 'none'", - "autoplay 'none'", - "camera 'none'", - "encrypted-media 'none'", - "fullscreen 'none'", - "geolocation 'none'", - "gyroscope 'none'", - "magnetometer 'none'", - "microphone 'none'", - "midi 'none'", - "payment 'none'", - "picture-in-picture 'none'", - "usb 'none'", - "sync-xhr 'none'", - ], + // While many of these features do not seem to have any security + // implication, deny them out of an abundance of caution to limit what + // injected or embedded content can reach. See + // https://github.com/w3c/webappsec-permissions-policy/blob/main/features.md + // for the features that exist. 'Permissions-Policy': [ 'accelerometer=()', - 'ambient-light-sensor=()', 'autoplay=()', - 'battery=()', 'camera=()', 'display-capture=()', - 'document-domain=()', 'encrypted-media=()', - 'execution-while-not-rendered=()', - 'execution-while-out-of-viewport=()', 'fullscreen=()', 'gamepad=()', 'geolocation=()', @@ -161,7 +145,6 @@ const config: HeadersConfig = { 'publickey-credentials-get=()', 'screen-wake-lock=()', 'serial=()', - 'speaker-selection=()', 'usb=()', 'web-share=()', 'xr-spatial-tracking=()', @@ -174,7 +157,6 @@ const config: HeadersConfig = { ], 'X-Content-Type-Options': ['nosniff'], 'X-Frame-Options': ['DENY'], - 'X-XSS-Protection': ['1', 'mode=block'], }, }, ], From db9968c7875249bc4cde7fffcb2d7ae703c80004 Mon Sep 17 00:00:00 2001 From: mm-kevcenteno Date: Fri, 31 Jul 2026 11:12:42 -0400 Subject: [PATCH 2/3] Keep denying sync-xhr after the Feature-Policy removal sync-xhr was denied only via Feature-Policy and had no Permissions-Policy counterpart, so removing that header dropped the denial entirely. Chrome still enforces Feature-Policy, and sync-xhr defaults to an allowlist of *, so this was blocking synchronous XHR in the top document and in every cross-origin frame. --- bin/_headers.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/_headers.config.ts b/bin/_headers.config.ts index b383d2c80..799777883 100644 --- a/bin/_headers.config.ts +++ b/bin/_headers.config.ts @@ -145,6 +145,7 @@ const config: HeadersConfig = { 'publickey-credentials-get=()', 'screen-wake-lock=()', 'serial=()', + 'sync-xhr=()', 'usb=()', 'web-share=()', 'xr-spatial-tracking=()', From 344762b4201e2d03163343c9ffe5e7c8296c6a76 Mon Sep 17 00:00:00 2001 From: mm-kevcenteno Date: Wed, 26 Aug 2026 15:49:04 -0400 Subject: [PATCH 3/3] Deny 53 more Permissions-Policy features This brings the policy to the same 76 features mm_website denies. The list was 22 features short of mm_website, and a further 31 recognized features were denied on none of the three sites. clipboard-write allows self because the copy button in assets/js/copy-markdown.ts calls navigator.clipboard.writeText. Every other addition is a flat deny. static/_headers is generated, so run npm run build:headers to pick this up. --- bin/_headers.config.ts | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/bin/_headers.config.ts b/bin/_headers.config.ts index 799777883..e290d4670 100644 --- a/bin/_headers.config.ts +++ b/bin/_headers.config.ts @@ -127,8 +127,41 @@ const config: HeadersConfig = { // for the features that exist. 'Permissions-Policy': [ 'accelerometer=()', + 'aria-notify=()', 'autoplay=()', + 'bluetooth=()', + 'browsing-topics=()', 'camera=()', + 'captured-surface-control=()', + 'ch-device-memory=()', + 'ch-downlink=()', + 'ch-dpr=()', + 'ch-ect=()', + 'ch-prefers-color-scheme=()', + 'ch-prefers-reduced-motion=()', + 'ch-prefers-reduced-transparency=()', + 'ch-rtt=()', + 'ch-save-data=()', + 'ch-ua=()', + 'ch-ua-arch=()', + 'ch-ua-bitness=()', + 'ch-ua-form-factors=()', + 'ch-ua-full-version=()', + 'ch-ua-full-version-list=()', + 'ch-ua-high-entropy-values=()', + 'ch-ua-mobile=()', + 'ch-ua-model=()', + 'ch-ua-platform=()', + 'ch-ua-platform-version=()', + 'ch-ua-wow64=()', + 'ch-viewport-height=()', + 'ch-viewport-width=()', + 'ch-width=()', + 'clipboard-read=()', + 'clipboard-write=(self)', + 'compute-pressure=()', + 'cross-origin-isolated=()', + 'digital-credentials-get=()', 'display-capture=()', 'encrypted-media=()', 'fullscreen=()', @@ -136,18 +169,38 @@ const config: HeadersConfig = { 'geolocation=()', 'gyroscope=()', 'hid=()', + 'identity-credentials-get=()', 'idle-detection=()', + 'interest-cohort=()', + 'join-ad-interest-group=()', + 'keyboard-map=()', + 'language-detector=()', + 'language-model=()', + 'local-fonts=()', + 'local-network=()', + 'local-network-access=()', + 'loopback-network=()', 'magnetometer=()', 'microphone=()', 'midi=()', + 'on-device-speech-recognition=()', + 'otp-credentials=()', 'payment=()', 'picture-in-picture=()', + 'private-state-token-issuance=()', + 'private-state-token-redemption=()', + 'publickey-credentials-create=()', 'publickey-credentials-get=()', + 'run-ad-auction=()', 'screen-wake-lock=()', 'serial=()', + 'summarizer=()', 'sync-xhr=()', + 'translator=()', + 'unload=()', 'usb=()', 'web-share=()', + 'window-management=()', 'xr-spatial-tracking=()', ], 'Referrer-Policy': ['strict-origin-when-cross-origin'],