# X-Frame-Options (/en/docs/web-security/security-headers/x-frame-options)



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`](/en/docs/web-security/policies/content-security-policy/directives/frame-ancestors)
directive does the same job with more control and supersedes it.

<Callout type="warn" title="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.
</Callout>

The safe default, blocking all framing:

```http
X-Frame-Options: DENY
```

## Quick overview [#quick-overview]

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

```http
X-Frame-Options: SAMEORIGIN
```

For new policies, prefer
[`frame-ancestors`](/en/docs/web-security/policies/content-security-policy/directives/frame-ancestors),
which expresses the same intent and more.

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

## Values [#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 [#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 [#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 [#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 [#relationship-to-frame-ancestors]

[`frame-ancestors`](/en/docs/web-security/policies/content-security-policy/directives/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.

```http
X-Frame-Options: SAMEORIGIN
```

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

## Known bypasses and limitations [#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 [#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 [#recommendation]

Send `X-Frame-Options: DENY` alongside a `frame-ancestors` directive unless the
page genuinely needs to be embedded.

```http
X-Frame-Options: DENY
```

```http
Content-Security-Policy: frame-ancestors 'none'
```

This is the
[OWASP HTTP Headers cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html)
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 [#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`.

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

```http
X-Frame-Options: SAMEORIGIN
```

3. Check both headers against your site with the
   [security headers scanner](/tools/security-headers).

## Browser support [#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 [#see-also]

* [frame-ancestors directive](/en/docs/web-security/policies/content-security-policy/directives/frame-ancestors)
* [Content-Security-Policy](/en/docs/web-security/policies/content-security-policy)
* [Security headers overview](/en/docs/web-security/security-headers)
* [X-Frame-Options vs frame-ancestors, which to use](/en/blog/x-frame-options-vs-frame-ancestors)
* [Legacy security headers to retire](/en/blog/legacy-security-headers-to-retire)
* [frame-ancestors without a CSP header](/en/blog/frame-ancestors-without-csp-header)

## Sources [#sources]

* [MDN, X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/X-Frame-Options)
* [W3C, Content Security Policy Level 3](https://www.w3.org/TR/CSP3/)
* [RFC 7034, HTTP Header Field X-Frame-Options](https://www.rfc-editor.org/rfc/rfc7034)
* [OWASP, HTTP Headers cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html)
