Clickjacking protection (X-Frame-Options / frame-ancestors)

The page can be embedded in a frame on any other site. An attacker can overlay your buttons with invisible decoys and trick logged-in users into clicking them (clickjacking).

Do this: Add frame-ancestors 'none' to the CSP. Without it your page can be loaded invisibly over an attacker's page, so a click lands on your button, not theirs.
PassFraming is restricted by X-Frame-Options or CSP frame-ancestors.
MediumNeither X-Frame-Options nor CSP frame-ancestors restricts framing of this page.

The fix, in one snippet

Example to adapt CSP is the modern form; keep XFO for old browsers
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY

Illustrative values. Change the paths, hostnames and options to match your own site before using it.

The sections below explain what is tested, why it matters and the alternatives.

What we test

Scan.now looks for two things on the response to /: an X-Frame-Options header with the value DENY or SAMEORIGIN, and a frame-ancestors directive in the Content-Security-Policy header. Either one passes; when both exist, frame-ancestors takes precedence in every current browser. The check fails when neither is present. It also flags ALLOW-FROM, an obsolete value that Chrome and Firefox treat as invalid and therefore as no protection, an X-Frame-Options delivered in a <meta> tag (browsers ignore it there), and multiple conflicting headers. Note that Scan.now tests the homepage; the header must be on every response, and the pages that matter most are the authenticated ones, such as settings and checkout.

Why it matters

Clickjacking (UI redressing) loads your page in a transparent iframe on the attacker's site and positions a real, working button, such as "Confirm transfer", "Delete account" or "Authorise app", directly under a harmless-looking decoy. The victim believes they clicked "Play video"; the browser delivered the click to your page with their cookies attached. Variants hijack drag-and-drop to move text out of the page and trick users into granting camera permissions. The attack needs the victim to be logged in, so it targets authenticated actions rather than public content. Cookies with SameSite=Lax reduce it, because a cross-site iframe load does not carry them and the framed page shows a logged-out state, but that protection depends on every session cookie having the attribute. The clickjacking guide walks through a full example.

How to fix it

Send both headers: frame-ancestors is the standard, X-Frame-Options covers older clients. nginx:

add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self'" always;

Apache:

Header always set X-Frame-Options "SAMEORIGIN"
Header always set Content-Security-Policy "frame-ancestors 'self'"

Express with Helmet (sets SAMEORIGIN and a CSP with frame-ancestors 'self' by default):

app.use(helmet());
// or just the framing header:
app.use(helmet.frameguard({ action: 'deny' }));

On Cloudflare, Rules > Settings > Managed Transforms > Add security headers adds X-Frame-Options: SAMEORIGIN at the edge. If a partner site legitimately embeds you, list it instead of blocking everything: frame-ancestors 'self' https://partner.example. If you already send a full Content-Security-Policy, append the directive to it rather than adding a second header; browsers apply all policies they receive and the most restrictive wins, which is usually what you want but can surprise you.

Where this fits

Clickjacking protection (X-Frame-Options / frame-ancestors) is check 2 of 13 that the website vulnerability scanner runs under http security headers, ordered the way they are worth fixing. That ordering is the point: Fixing this one while the check above it still fails buys less than it looks like.

Fix this one first

Above it in the same category sits CORS allows arbitrary origins with credentials (high), where the server reflects any Origin in Access-Control-Allow-Origin while also sending Access-Control-Allow-Credentials: True. An attacker who has that does not need this, so it is the better use of the same hour.

What fixing this still leaves open

Clickjacking protection (X-Frame-Options / frame-ancestors) closes one route in. Immediately below it: Content-Security-Policy is weak, where a Content-Security-Policy exists but contains directives that let injected script run anyway: 'unsafe-inline' without nonces, 'unsafe-eval', wildcards, data: URIs, or missing object-src and base-uri; Content-Security-Policy missing, where the page is served without an enforced Content-Security-Policy; Cross-Origin-Opener-Policy, where the page does not set Cross-Origin-Opener-Policy, so windows it opens, or that open it, from other origins keep a reference to it and share its browsing context group.

Found in the same scan

The website vulnerability scanner reports this alongside checks from other categories that are at least as serious, including Certificate chain and hostname validation, where the certificate presented for this hostname did not validate: The chain does not reach a trusted root, an intermediate is missing, the name does not match, or the certificate is self-signed or expired, and Exposed .env configuration file, where a .env configuration file is served from the web root. A single run of website vulnerability scanner answers all of them at once.

Prompt for an AI Hand this check to an assistant Sign in to copy it
The first few lines
You are a senior web engineer. I ran a security and SEO scanner against my site and it reported the finding below. Fix it properly rather than suppressing the symptom.

Finding: Clickjacking protection (X-Frame-Options / frame-ancestors) (medium severity)
Scanner check id: x-frame-options
18 more lines, including the evidence and the exact fix

The rest of this prompt names the pages and line numbers we found the problem on, the configuration to change, and the constraints a good answer has to respect. It is free, it just needs an account so the work is not scraped wholesale.

Sign in with Google

Signing in is free and takes one click. We store your email address and nothing else.

References

  1. MDN: X-Frame-Options
  2. MDN: CSP frame-ancestors
  3. OWASP Clickjacking Defense Cheat Sheet
  4. RFC 7034: HTTP Header Field X-Frame-Options

Related guides