Back to HTTP Headers

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-OptionsALLOW-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.