X-Frame-Options security response
Controls whether the browser can render this page inside an iframe — preventing clickjacking attacks.
What it does
X-Frame-Options tells the browser whether it's allowed to render this page inside a <frame>, <iframe>, <object>, or <embed> element. Its purpose is preventing clickjacking attacks — where an attacker embeds your page invisibly inside their page and tricks users into clicking buttons on your site while thinking they're interacting with something else.
A classic example: an attacker overlays your bank's "Transfer Money" button under a fake "Win a Prize" button. The user clicks what they see; they're actually clicking your bank's button while invisibly authenticated via their open session.
Syntax
X-Frame-Options: DENY
X-Frame-Options: SAMEORIGIN
Note: The ALLOW-FROM directive existed but was never fully implemented and is deprecated. Use CSP frame-ancestors for allowlisting specific origins.
Directives
DENY
The page cannot be displayed in a frame under any circumstances — not by the same site, not by any other site.
X-Frame-Options: DENY
Use for pages that should never be framed: login pages, payment flows, admin dashboards, account settings. Most security-sensitive pages should use DENY.
SAMEORIGIN
The page can be embedded in a frame, but only by pages on the same origin (same scheme, host, and port).
X-Frame-Options: SAMEORIGIN
Use when you legitimately embed your own pages in iframes — some UIs and portals do this.
X-Frame-Options vs CSP frame-ancestors
X-Frame-Options is superseded by Content-Security-Policy: frame-ancestors for modern browsers:
X-Frame-Options |
CSP frame-ancestors |
|
|---|---|---|
| Browser support | Universal (IE6+) | Modern browsers only |
| Allow specific origins | No (ALLOW-FROM deprecated) | Yes (frame-ancestors https://partner.com) |
| Multiple origins | No | Yes (frame-ancestors 'self' https://a.com https://b.com) |
| Meta tag support | No | No (header only) |
| Overrides | Not by CSP | Overrides X-Frame-Options |
Best practice: set both. CSP: frame-ancestors for modern browsers; X-Frame-Options as a fallback for older ones. If both are set, frame-ancestors takes precedence in browsers that support it.
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
Clickjacking in practice
The attack flow:
<!-- Attacker's page -->
<style>
iframe { opacity: 0; position: absolute; top: 100px; left: 200px; }
.fake-button { position: absolute; top: 100px; left: 200px; }
</style>
<button class="fake-button">Claim Your Prize!</button>
<iframe src="https://yourbank.com/transfer?amount=1000&to=attacker"></iframe>
The user sees "Claim Your Prize!" and clicks it. The transparent iframe under it registers the click on your bank's transfer confirmation button — with the user's active session.
X-Frame-Options: DENY prevents the iframe from loading in the first place.
Common mistakes and gotchas
Setting SAMEORIGIN when you mean DENY. If your login page has no legitimate reason to be embedded in any iframe, use DENY. SAMEORIGIN still allows embedding within your own site, which could be a risk depending on your application architecture.
Relying only on X-Frame-Options. For modern setups, add CSP: frame-ancestors too. Some newer browser features only check CSP, not X-Frame-Options.
Not setting it at all on auth pages. Clickjacking is most dangerous on authenticated pages that perform actions. Login forms, payment confirmations, delete/destructive actions, and settings changes are highest priority.
Sending multiple X-Frame-Options headers. Some frameworks or middleware stacks add it multiple times. When there are multiple X-Frame-Options headers, browser behaviour varies — some use the first, some use the most restrictive, some reject all. Only send it once.
Real-world examples
Login page — no framing ever:
HTTP/1.1 200 OK
X-Frame-Options: DENY
Content-Security-Policy: frame-ancestors 'none'
App with same-origin embedding:
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
Content-Security-Policy: frame-ancestors 'self'
Partner portal — allow specific third-party embedding:
HTTP/1.1 200 OK
Content-Security-Policy: frame-ancestors 'self' https://partner.example.com
X-Frame-Options can't express this. CSP only for this case.
FAQ
Does X-Frame-Options protect against all clickjacking variants?
It protects against iframe-based clickjacking. It doesn't protect against drag-and-drop clickjacking, touch event hijacking, or other cursor/input hijacking vectors. Defence in depth (CSRF tokens, SameSite cookies, user re-confirmation for sensitive actions) is still necessary.
Can I use X-Frame-Options to allow specific external sites to embed my page?
Not with X-Frame-Options — ALLOW-FROM is deprecated and poorly supported. Use Content-Security-Policy: frame-ancestors https://trusted-partner.com for this use case.
Does this affect how my page loads iframes from other sites?
No — X-Frame-Options and frame-ancestors only control whether your page can be embedded by others. To control what your page can embed, use CSP: frame-src.
Fun fact
X-Frame-Options is one of the most widely deployed security headers on the web, despite never being part of an official HTTP standard until RFC 7034 in 2013 — more than five years after it was first implemented. It was originally introduced by Microsoft in Internet Explorer 8 in 2008 as a proprietary extension to address clickjacking, which had been publicly disclosed by Jeremiah Grossman and Robert Hansen at OWASP AppSec 2008. Other browsers adopted it informally before any spec existed — a pattern common in web security where browser vendors and security researchers move faster than standards bodies.