CentralCSP
Security headers

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: DENY

Quick overview

SAMEORIGIN lets only pages on your own origin frame you; DENY blocks all framing.

X-Frame-Options: SAMEORIGIN

For new policies, prefer frame-ancestors, which expresses the same intent and more.

Content-Security-Policy: frame-ancestors 'self'

Values

ValueStatusWhat it does
DENY✅ GoodNo site may frame the page, including the page's own origin.
SAMEORIGIN✅ GoodOnly pages from the same origin may frame the page.
ALLOW-FROM uri⚠️ DeprecatedObsolete 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-Optionsframe-ancestors equivalent
DENYframe-ancestors 'none'
SAMEORIGINframe-ancestors 'self'
ALLOW-FROM https://a.exampleframe-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: SAMEORIGIN
Content-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: DENY
Content-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

  1. Add frame-ancestors to your CSP with the parents you allow ('none', 'self', or specific origins).
  2. Optionally send X-Frame-Options as well, for browsers that predate CSP frame-ancestors.
Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN
  1. 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

Sources

On this page