# X-Frame-Options or CSP frame-ancestors is set

- **Pattern:** `ab-000007` (`security-headers.headers.x-frame-options`)
- **Severity:** medium
- **Lifecycle:** active
- **Last modified:** 2026-04-17
- **Canonical URL:** https://auditbuffet.com/patterns/ab-000007
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-000007)

## Why it matters

Clickjacking embeds your app inside an attacker-controlled `<iframe>`, then overlays a transparent UI that tricks users into clicking buttons they can't see — authorizing transactions, enabling permissions, or deleting accounts on your behalf. The attack requires zero user credentials and is invisible to the victim. Without framing protection, any page on your site is a potential weapon: login buttons, payment confirmations, settings toggles. CAPEC-103 documents the attack pattern in detail. OWASP A05 identifies missing framing controls as a security misconfiguration. `X-Frame-Options: DENY` is a single-line fix that eliminates the entire attack surface.

## Severity rationale

Medium because clickjacking requires attacker-controlled page delivery but can silently authorize destructive actions on behalf of authenticated users.

## Remediation

Add either `X-Frame-Options` or the CSP `frame-ancestors` directive. `frame-ancestors` is preferred in modern configs because it's more expressive and part of CSP Level 2.

```js
// next.config.js — choose one approach
headers: [
  // Option A: legacy X-Frame-Options
  { key: 'X-Frame-Options', value: 'DENY' },
  // Option B: CSP frame-ancestors (more flexible)
  { key: 'Content-Security-Policy', value: "frame-ancestors 'none'" }
]
```

Use `DENY` / `'none'` if your site never needs to appear in an iframe. Use `SAMEORIGIN` / `'self'` if you embed your own pages. Do not use `ALLOW-FROM` — it is deprecated and ignored by modern browsers.

## Detection

- **ID:** `x-frame-options`
- **Severity:** `medium`
- **What to look for:** Count the clickjacking protection mechanisms present: `X-Frame-Options` header (value `DENY` or `SAMEORIGIN`) and CSP `frame-ancestors` directive. At least 1 mechanism is required.
- **Pass criteria:** At least 1 of the following is configured: `X-Frame-Options` header set to `DENY` or `SAMEORIGIN` (the deprecated `ALLOW-FROM` value does not count), OR CSP includes a `frame-ancestors` directive with explicit origins (e.g., `frame-ancestors 'self'` or `frame-ancestors 'none'`). Either mechanism is sufficient; both together is ideal. 100% of page routes should be covered by the framing protection.
- **Fail criteria:** Neither `X-Frame-Options` nor CSP `frame-ancestors` is configured anywhere in the project.
- **Skip (N/A) when:** Never — clickjacking protection applies to all web projects.
- **Detail on fail:** `"No X-Frame-Options header or CSP frame-ancestors directive found — site is vulnerable to clickjacking"`
- **Remediation:** These headers prevent your site from being embedded in an iframe on another domain, protecting against clickjacking attacks:

  ```js
  headers: [{
    key: 'X-Frame-Options',
    value: 'DENY'
  }]
  ```

  Or use CSP: `frame-ancestors 'self'`. Use `DENY` if your site never needs to be framed. Use `SAMEORIGIN` if you frame your own pages.

## External references

- cwe CWE-1021
- capec CAPEC-103
- owasp A05

Taxons: injection-and-input-trust

HTML version: https://auditbuffet.com/patterns/ab-000007
