X-Frame-Options: how to stop your pages being framed
With no X-Frame-Options and no frame-ancestors, any site can iframe your pages and overlay them. squirrel checks both headers together.
What X-Frame-Options is
X-Frame-Options is a response header that tells the browser whether the page may be loaded inside a <frame>, <iframe>, <embed> or <object>. DENY refuses all framing, SAMEORIGIN allows it only from the same origin. Without one, an attacker can load your page invisibly over their own and capture clicks meant for their interface, which is clickjacking.
The header is superseded by the CSP frame-ancestors directive, which supports a source list rather than a single keyword and is the one modern browsers consult first. The ALLOW-FROM value never worked in Chrome and was removed from the others. Sending both headers is still common for older clients.
What squirrel checks
The rule reads the response headers of the first crawled page and emits a single check named x-frame-options:
- Skipped when the crawl produced no pages. Message:
No pages to check. - Pass when
X-Frame-OptionsisDENYorSAMEORIGIN, compared case-insensitively. Message:X-Frame-Options header present, with the raw value. - Warn when the value contains
ALLOW-FROM. Message:ALLOW-FROM is deprecated, withUse CSP frame-ancestors insteadas the value. - Pass when there is no
X-Frame-Optionsheader but theContent-Security-Policyheader containsframe-ancestors. Message:Clickjacking protection via CSP frame-ancestors. - Warn when neither is present. Message:
No clickjacking protection, withAdd X-Frame-Options: DENY or CSP frame-ancestorsas the value.
An X-Frame-Options value that is neither of the two keywords nor contains ALLOW-FROM produces no check at all, so a typo shows up as a missing result rather than a warning.
How to fix it
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
Set both on every HTML response. Use frame-ancestors 'none' and DENY when nothing should ever frame the page. If a partner genuinely embeds you, list their origin in frame-ancestors rather than dropping the header, and keep SAMEORIGIN as the legacy fallback.
| Rule ID | security/x-frame-options |
| Category | Security |
| Scope | Site-wide |
| Severity | warning |
| Weight | 5/10 |
Enable / disable
Disable this rule
[rules]
disable = ["security/x-frame-options"]Disable all Security rules
[rules]
disable = ["security/*"]Enable only this rule
[rules]
enable = ["security/x-frame-options"]enable replaces the default ["*"], so this is the only rule selected. Leave disable out: a rule that matches any disable pattern is skipped even when enable names it. Only an enabled setting under a rule’s own [rule_options] table overrides both lists.
Related rules
- security/csp: where
frame-ancestorslives and what else the policy should say. - security/x-content-type: the other one-line response header worth setting at the same time.
- security/permissions-policy: what an embedded frame is allowed to access.
- integrity/fake-auth-overlay: overlays served from your own pages rather than framed from outside.
Security findings ship in every audit next to the SEO, performance and agent experience rules. See Website security scan with AI for how an agent works through a report.
References
Check your site
Run squirrel audit https://example.com and open the Security section of the report. Framing protection is reported once for the site, with the header value your server sent. Signed-out local audits need no account and cost nothing. Signed-in audits spend credits.