Skip to content

Align X-Frame-Options with CSP and add missing X-XSS-Protection header#597

Open
flightlesstux wants to merge 1 commit intopassbolt:masterfrom
flightlesstux:fix/security-headers-consistency
Open

Align X-Frame-Options with CSP and add missing X-XSS-Protection header#597
flightlesstux wants to merge 1 commit intopassbolt:masterfrom
flightlesstux:fix/security-headers-consistency

Conversation

@flightlesstux
Copy link

Problem

Two inconsistencies in the SecurityHeadersMiddleware configuration in Application::middleware():

1. X-Frame-Options too permissive

setXFrameOptions() is called without arguments, which defaults to SAMEORIGIN. The comment directly above reads "Don't allow framing the site", and ContentSecurityPolicyMiddleware already sets frame-ancestors 'none' in the default CSP — which prohibits all framing including same-origin.

The X-Frame-Options header was weaker than the declared CSP policy, creating an inconsistency:

Header Value Effect
Content-Security-Policy frame-ancestors 'none' No framing, any origin
X-Frame-Options (before) SAMEORIGIN Same-origin framing allowed

X-Frame-Options is the legacy fallback for browsers that don't support CSP frame-ancestors. It should match the stricter CSP intent.

2. X-XSS-Protection never set

The comment block reads "Tell browser to block XSS attempts" but setXssProtection() was never called. The X-XSS-Protection header was absent from all responses.

Fix

$headers
    ->setCrossDomainPolicy()
    ->setReferrerPolicy()
    ->setXFrameOptions('deny')   // was: setXFrameOptions() → SAMEORIGIN
    ->setXssProtection()         // was: missing
    ->noOpen()
    ->noSniff();

Impact

  • X-Frame-Options: DENY now matches the CSP frame-ancestors 'none' policy across all browsers including those without CSP support
  • X-XSS-Protection: 1; mode=block added for legacy browser defence-in-depth
  • No impact on modern browsers that enforce CSP

Two issues in the SecurityHeadersMiddleware configuration:

1. setXFrameOptions() was called without an argument, which defaults
   to SAMEORIGIN. The comment above explicitly states 'Don't allow
   framing the site', and ContentSecurityPolicyMiddleware already sets
   'frame-ancestors none' in the CSP. The X-Frame-Options header was
   inconsistently weaker than the declared CSP policy.
   Fix: pass 'deny' to match the intent and the CSP.

2. The comment 'Tell browser to block XSS attempts' was present but
   setXssProtection() was never called, leaving X-XSS-Protection
   absent from responses. While modern browsers rely on CSP over this
   legacy header, it provides defence-in-depth for older user agents.
   Fix: add ->setXssProtection() to the chain.
@CLAassistant
Copy link

CLAassistant commented Mar 12, 2026

CLA assistant check
All committers have signed the CLA.

@Gamabunta57
Copy link
Member

Hi @flightlesstux !

Thank you for this pull request.

This is interesting indeed. I think, yes, X-Frame-Options could be set to deny and has no negative impact after a quick check.

However, for the second one, I can't agree. It sounds good at first sight but when reading https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-XSS-Protection it feels like we should not go with this one. Plus according to the Browser compatibility section, this header is not supported anymore (the latest browser that supported it was Microsoft Edge in 2015).

So, I would go for the X-Frame-Options but not the second one.

Cheers

@Gamabunta57
Copy link
Member

For information, it's now under review for a merge with the ticket PB-50070.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants