347 Fill the gaps in the response security headers - #349
Merged
Conversation
A security assessment picked up a handful of low-severity header and cookie items. Individually each is minor; together they are the cheapest security work available, and several had been noted informally for a while. The existing set was most of the way there — HSTS, a content-security policy and X-Frame-Options were already in place, and the session cookie already sets Secure outside development. This fills what was missing rather than starting from nothing: - X-Content-Type-Options: nosniff, so a browser stops second-guessing a declared content type. It matters here because the storage browser and the content pipeline both serve files an author supplied. - Referrer-Policy: strict-origin-when-cross-origin. Without it the full URL, window and request identifiers included, travels to any third-party origin in the Referer header. Same-origin navigation is unaffected. - Permissions-Policy denying camera, microphone, geolocation and the rest. The service asks for none of them, so an injected frame or script cannot ask on its behalf either. - The antiforgery cookie now follows the same environment-dependent Secure policy the session cookie already had; it had been left on the default. SameAsRequest in development keeps local HTTP working, where Always would have the browser drop the cookie and fail every form POST. - TRACE is refused with 405 before routing. Cross-site tracing is already closed by HttpOnly cookies and modern browsers, so this removes a surface rather than fixing an exploit. - Kestrel no longer advertises itself. The banner carries no version, but naming the stack tells a scanner which exploits are worth trying and buys nothing. The headers moved into one middleware. They only do anything if they are on every response, and spread across controllers a new endpoint silently misses them. The content-security policy moved there unchanged and is pinned by a test so folding it in cannot quietly drop it. Headers are assigned rather than appended: appending to one something upstream already set produces two of it, and a browser given two conflicting security headers may pick the one we did not want. Left alone deliberately: 'unsafe-inline' and 'unsafe-eval' in the policy's script-src. Removing them means threading a per-request nonce through every inline script and style, including those the frontend toolkit and the analytics tags emit — real regression risk that deserves its own change and its own testing rather than riding along with a header sweep. Refs #347
|
Review app for PR 349 was deleted |
paulc1983
approved these changes
Aug 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #347.
A security assessment picked up a handful of low-severity header and cookie
items. Individually each is minor; together they are the cheapest security work
available, and several had been noted informally for a while.