> ## Documentation Index
> Fetch the complete documentation index at: https://docs.37audits.com/llms.txt
> Use this file to discover all available pages before exploring further.

# X-Frame-Options Auditor

> Checks that other sites cannot load your page in a frame (clickjacking)

<Info>
  **Security Auditor** — checks that the audited page sends `X-Frame-Options: DENY` or `SAMEORIGIN`, or a `Content-Security-Policy` with `frame-ancestors`, so other sites cannot embed it in a frame.
</Info>

<CardGroup cols={2}>
  <Card title="Protection" icon="shield-halved">
    Stops attackers from loading your page in a hidden frame and tricking visitors into clicking it.
  </Card>

  <Card title="Standards" icon="book">
    Follows the X-Frame-Options section of the WHATWG HTML Living Standard and honors CSP `frame-ancestors`.
  </Card>
</CardGroup>

In a clickjacking attack, a malicious page loads your site in an invisible frame and places its own buttons on top, so a visitor who thinks they are clicking the attacker's page is really clicking yours: confirming a payment, changing a setting or sharing data. Browsers refuse to frame a page that forbids it with `X-Frame-Options` or with the `frame-ancestors` directive of `Content-Security-Policy`. This auditor reads both headers from the audited URL.

## How it works

1. **Fetch** — sends a `HEAD` request (or `GET` when `HEAD` is not supported) to the audited URL as 37AuditsBot. A blocked request ends the audit with `590`; any other failure (timeout, DNS, TLS, non-2xx answer) ends it with `500`.
2. **CSP first** — when an enforced `Content-Security-Policy` header (not `Content-Security-Policy-Report-Only`) has a `frame-ancestors` directive, browsers ignore `X-Frame-Options`, so the page passes. A `frame-ancestors *` alone allows every site and does not count.
3. **Read** — like browsers, collects every `X-Frame-Options` header line, splits it on commas, trims and lowercases each value and drops duplicates. `DENY, DENY` is read as `deny`.
4. **Rules** — a missing header (`400`), the obsolete `ALLOW-FROM` (`401`) and any other value that is not `DENY` or `SAMEORIGIN`, such as `ALLOWALL` (`402`), fail. Several distinct values that include `DENY`, `SAMEORIGIN` or `ALLOWALL` warn (`300`): browsers then block every frame.
5. **Aggregate** — FAIL wins over WARNING; when every rule passes the audit is `SUCCESS` (`200`).
6. **Specification pin** — every run emits `37A-XFrameOptionsAuditor-100` (`INFORMATION`), naming the [X-Frame-Options section of the WHATWG HTML Living Standard](https://html.spec.whatwg.org/multipage/document-lifecycle.html#the-x-frame-options-header) as of 2026-10-15. It does not change the overall status.

## What it audits

Every row maps to one `checkRule*` method and one `CheckCode`, in the order the auditor runs them. CheckCode suffixes use status ranges: `100` information, `200` success, `300–399` warning, `400–499` fail, `500–599` error.

| CheckCode | Status | When it fires | Recommendation | Why it matters |
| - | - | - | - | - |
| <a id="37A-XFrameOptionsAuditor-100" />`37A-XFrameOptionsAuditor-100` | `INFORMATION` | Always. Records the specification version this auditor implements. | — (recommendation is `null`; nothing for the site to change) | — |
| <a id="37A-XFrameOptionsAuditor-400" />`37A-XFrameOptionsAuditor-400` | `FAIL` | The page sends no `X-Frame-Options` value and no CSP `frame-ancestors`. | Add "X-Frame-Options: SAMEORIGIN" (or DENY) or "Content-Security-Policy: frame-ancestors 'self'" to the responses of `{url}`. | Without frame protection, attackers can load your site in a hidden frame and trick visitors into clicking buttons they cannot see (clickjacking). |
| <a id="37A-XFrameOptionsAuditor-401" />`37A-XFrameOptionsAuditor-401` | `FAIL` | Every `X-Frame-Options` value is `ALLOW-FROM …`, which current browsers ignore. | Replace "`{value}`" with "Content-Security-Policy: frame-ancestors 'self' `{origin}`" to allow only `{origin}`. | Browsers dropped ALLOW-FROM, so the page has no frame protection and is open to clickjacking. |
| <a id="37A-XFrameOptionsAuditor-402" />`37A-XFrameOptionsAuditor-402` | `FAIL` | The value is not `DENY` or `SAMEORIGIN` (for example `ALLOWALL` or a typo), so browsers ignore it. | Replace "`{value}`" with "SAMEORIGIN" or "DENY" in the X-Frame-Options header of `{url}`. | Browsers ignore this value, so the page is as exposed to clickjacking as if the header were missing. |
| <a id="37A-XFrameOptionsAuditor-300" />`37A-XFrameOptionsAuditor-300` | `WARNING` | The header carries several distinct values that include `DENY`, `SAMEORIGIN` or `ALLOWALL`. | Send a single value ("SAMEORIGIN" or "DENY") instead of "`{value}`" on `{url}`; check for a duplicate header added by the server and a proxy or CDN. | Conflicting values usually mean two layers set the header; browsers then block all framing, which can break your own embedded pages. |
| <a id="37A-XFrameOptionsAuditor-200" />`37A-XFrameOptionsAuditor-200` | `SUCCESS` | All rules passed. Message names the `X-Frame-Options` value or the CSP `frame-ancestors` sources that protect the page. | — | — |
| <a id="37A-XFrameOptionsAuditor-500" />`37A-XFrameOptionsAuditor-500` | `ERROR` | The page could not be fetched (timeout, DNS, TLS, or a non-2xx answer other than a block). | Make sure `{url}` answers with HTTP 2xx, then run the audit again. Last error: `{error}`. | — |
| <a id="37A-XFrameOptionsAuditor-590" />`37A-XFrameOptionsAuditor-590` | `ERROR` | The audited page answered HTTP 403, HTTP 429 or a Cloudflare challenge, so 37AuditsBot was blocked before it could read the page. | Allow 37AuditsBot in your firewall or bot protection: allowlist its user agent, or verify its Web Bot Auth signature. See [https://www.37audits.com/bot](https://www.37audits.com/bot). | While 37AuditsBot is blocked this audit cannot look at the site, so problems on it go unreported. |

## Output documentation

| Status | Description | Test logic |
| - | - | - |
| **SUCCESS** | Other sites cannot frame this page | `X-Frame-Options` is `DENY` or `SAMEORIGIN` (any letter case), or an enforced CSP has a restricting `frame-ancestors` (`200`). |
| **WARNING** | Framing is blocked, including your own pages | Conflicting `X-Frame-Options` values (`300`). |
| **FAIL** | Any site can frame this page | Missing header (`400`); `ALLOW-FROM` (`401`); any other value that is not `DENY` or `SAMEORIGIN` (`402`). |
| **ERROR** | The auditor could not read the page | Fetch failure or non-2xx answer (`500`); site blocked 37AuditsBot (`590`). |
| **INFORMATION** | Specification pin | Always emitted (`100`); does not change overall status. |

## Risks and considerations

### Why clickjacking matters

* Any page where a single click does something (buy, delete, transfer, share, change a password or a permission) can be abused while it sits in a hidden frame on another site.
* Login and account pages are the most valuable targets, but the protection is cheap enough to send on every page.

### DENY, SAMEORIGIN or CSP

* `DENY` forbids every frame; `SAMEORIGIN` allows only pages of your own origin.
* `ALLOW-FROM` was never supported by Chrome or Safari and Firefox dropped it, so it gives no protection. To allow specific partner sites, use `Content-Security-Policy: frame-ancestors 'self' https://partner.example`.
* When `frame-ancestors` is present, browsers ignore `X-Frame-Options`. Many sites send both so older browsers stay protected.

### Duplicate headers

* A web server and a CDN or proxy that both add the header produce values such as `SAMEORIGIN, DENY`. Browsers treat that as a conflict and refuse every frame, which can break pages you embed yourself.

### What this auditor does not check

* Only the audited URL is fetched; other pages of the site may be sent without the header.
* `Content-Security-Policy` set in an HTML `<meta>` tag is not read: browsers ignore `frame-ancestors` there.
* The sources listed in `frame-ancestors` are not judged, apart from a lone `*`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.