X-Frame-Options
The X-Frame-Options header (DENY, SAMEORIGIN) and how the CSP frame-ancestors directive supersedes it for clickjacking protection.
Last update:
The X-Frame-Options header tells the browser whether a page may be loaded inside
a frame, the original defense against clickjacking. It takes one of two values,
DENY or SAMEORIGIN. The Content Security Policy (CSP)
frame-ancestors
directive does the same job with more control and supersedes it.
ALLOW-FROM is obsolete
The old ALLOW-FROM uri value is obsolete and no longer honored by modern browsers. To allow specific origins to frame your page, use the CSP frame-ancestors directive instead, which takes a source list.
The safe default, blocking all framing:
X-Frame-Options: DENYQuick overview
SAMEORIGIN lets only pages on your own origin frame you; DENY blocks all
framing.
X-Frame-Options: SAMEORIGINFor new policies, prefer
frame-ancestors,
which expresses the same intent and more.
Content-Security-Policy: frame-ancestors 'self'Values
| Value | Status | What it does |
|---|---|---|
DENY | ✅ Good | No site may frame the page, including the page's own origin. |
SAMEORIGIN | ✅ Good | Only pages from the same origin may frame the page. |
ALLOW-FROM uri | ⚠️ Deprecated | Obsolete and ignored by modern browsers; use frame-ancestors. |
The header takes a single value, not a list. That single-origin limit is the
reason ALLOW-FROM failed: there was no way to allow more than one parent origin.
frame-ancestors accepts a full source list, so it covers every case the header
cannot.
Insecure values to avoid
The value to avoid is ALLOW-FROM, because browsers ignore it: a page relying on
it for protection is effectively unprotected. Sending no framing control at all is
the other gap. It leaves the page embeddable by any site and open to clickjacking.
Set DENY or SAMEORIGIN, or better, frame-ancestors.
Why this header exists
X-Frame-Options predates CSP and was the first browser mechanism to stop
clickjacking, where an attacker frames your page invisibly and tricks a user into
clicking it. It works, but it is coarse: one value, one origin, no source list.
CSP later folded the same protection into the frame-ancestors directive with a
proper source list, which is why the header is now considered legacy.
What it protects against
Clickjacking, also called UI redressing. An attacker loads your page in a transparent or disguised frame over their own content and captures clicks meant for their page as actions on yours. Restricting who may frame the page removes the overlay.
Relationship to frame-ancestors
frame-ancestors
supersedes X-Frame-Options. Where both are present and the browser supports CSP
frame-ancestors, the directive takes precedence and the header is ignored. The
values map directly:
| X-Frame-Options | frame-ancestors equivalent |
|---|---|
DENY | frame-ancestors 'none' |
SAMEORIGIN | frame-ancestors 'self' |
ALLOW-FROM https://a.example | frame-ancestors https://a.example |
Sending both is still reasonable: frame-ancestors governs modern browsers, and
X-Frame-Options covers any old client that does not honor the directive.
X-Frame-Options: SAMEORIGINContent-Security-Policy: frame-ancestors 'self'Known bypasses and limitations
X-Frame-Options only controls top-level framing of the response it is sent on;
it cannot express a list of allowed parents (ALLOW-FROM is dead), and it does not
report anything. frame-ancestors has neither limit. Note that frame-ancestors,
unlike most CSP directives, cannot be set via a <meta> tag, so framing control is
always an HTTP response header.
Risks of misconfiguration
Relying on ALLOW-FROM leaves the page unprotected because browsers drop it.
Omitting both the header and frame-ancestors leaves the page framable by anyone.
Choose DENY when the page should never be embedded, SAMEORIGIN (or
frame-ancestors 'self') when only your own app embeds it.
Recommendation
Send X-Frame-Options: DENY alongside a frame-ancestors directive unless the
page genuinely needs to be embedded.
X-Frame-Options: DENYContent-Security-Policy: frame-ancestors 'none'This is the
OWASP HTTP Headers cheat sheet
recommendation: frame-ancestors takes precedence in the browsers that support
it, and the header covers any old client that does not.
How to set it up
- Add
frame-ancestorsto your CSP with the parents you allow ('none','self', or specific origins). - Optionally send
X-Frame-Optionsas well, for browsers that predate CSPframe-ancestors.
Content-Security-Policy: frame-ancestors 'self'X-Frame-Options: SAMEORIGIN- Check both headers against your site with the security headers scanner.
Browser support
Widely supported. DENY and SAMEORIGIN work across modern browsers;
ALLOW-FROM is obsolete and ignored. CSP frame-ancestors is also widely
supported and is the preferred control.
See also
- frame-ancestors directive
- Content-Security-Policy
- Security headers overview
- X-Frame-Options vs frame-ancestors, which to use
- Legacy security headers to retire
- frame-ancestors without a CSP header
Sources
Cross-Origin-Resource-Policy
CORP lets a resource say who may embed it, protecting against cross-origin leaks and hotlinking. Values and how it pairs with COEP.
Information disclosure
Server, X-Powered-By, and the other headers that leak your stack and versions to attackers, the full list and how to remove them.