Defaults.Exposed

Defaults.ExposedReports

What Is Clickjacking? X-Frame-Options and How to Stop It

Published

Clickjacking is a browser attack that loads your real website invisibly inside a page the attacker controls, then tricks a visitor into clicking something on your site they never meant to click — approving a payment, changing a setting, confirming a permission — while they believe they are clicking a harmless button on the attacker’s page. It is stopped by one thing: telling browsers who is allowed to frame your pages, using either the X-Frame-Options response header or the modern Content-Security-Policy: frame-ancestors directive. The August 2026 defaults.exposed census graded 284,598,752 domains on their web-security posture and found the frame defense is thin on the ground: only 8.0% set any Content-Security-Policy — the header that carries the modern frame-ancestors control — and under 1% deploy the cross-origin isolation headers that harden framing further. For most of the web, nothing at the header layer stops an attacker from putting your page inside a frame.

If you have never set a frame-protection header, your site is almost certainly framable right now — and you can confirm it in about 30 seconds. Whether that matters depends on what a logged-in visitor can do on your pages with a single click, but the defense costs one line of server configuration and breaks nothing for the overwhelming majority of sites. The figures throughout come from the defaults.exposed August 2026 census, an independent scan of 432,127,908 domains graded as of 2026-08-16.


What is clickjacking?

Clickjacking — also called a UI-redress attack or UI redressing — is a technique where an attacker overlays or embeds your legitimate web page inside their own malicious page and manipulates what the visitor sees, so a click intended for the attacker’s decoy actually lands on a control inside your framed site.

The visitor’s browser is genuinely authenticated to your site. If they are logged in — to a bank, a router admin panel, a social account, a SaaS dashboard — the framed page carries their real session. A click they think does one thing does another, entirely inside your trusted origin, with their real credentials attached.

The name dates to 2008, but the class of attack has only broadened since: anywhere a single click performs a meaningful action, an attacker who can frame that page can try to steal the click. The defense has nothing to do with your login system or your firewall. It is a browser instruction, delivered in an HTTP response header, that says this page may not be framed by strangers. Publish it and the attack becomes impossible; omit it and the browser assumes framing is fine.

Two headers carry that instruction. The older one is X-Frame-Options; the modern one is the frame-ancestors directive of Content-Security-Policy. Both are graded by defaults.exposed — see the X-Frame-Options methodology and the Content-Security-Policy methodology for exactly how each is scored.


How a clickjacking (UI-redress) attack works

The mechanics are simple, which is part of why the attack persists. A clickjacking page needs three ingredients, and none of them require breaking into your systems:

  1. A frame. The attacker embeds your page in an <iframe> on a site they control. This is ordinary HTML — the browser will do it unless your page’s headers forbid it.
  2. Invisibility. They set the frame’s opacity to zero, or slide it partly off-screen, or stack a decoy element beneath it with CSS z-index. The victim sees the attacker’s bait — “Click here to claim your prize”, “Play video”, “I am not a robot” — but their cursor is actually hovering over a control on your framed page.
  3. Alignment. The attacker positions the invisible frame so that the button the victim is lured into clicking sits exactly over a sensitive action on your site: a “Confirm transfer”, “Authorize app”, “Delete”, or “Change email” button.

The victim clicks the visible bait. The click passes through to the invisible layer and triggers the real action on your domain, authenticated as them. Nothing on your server looks abnormal — it was a legitimate, authenticated request from a real browser. The deception happened entirely in the rendering.

Variants refine the same idea. Likejacking steals clicks on social “like” or “follow” widgets. Cursorjacking displaces the visible cursor from the real pointer position so the victim misjudges where they are clicking. Drag-and-drop clickjacking coaxes a victim into dragging data out of a framed field. All of them depend on one precondition: that the target page can be framed at all. Remove that precondition and every variant collapses.


X-Frame-Options: the classic frame-busting header

X-Frame-Options (standardized in RFC 7034) was the browser world’s first dedicated anti-framing control. It is a response header your server sends with each page, and it takes one of two meaningful values:

A third value, ALLOW-FROM <origin>, once let you name a single permitted framing origin. It is obsolete — never fully supported across browsers and now ignored by all modern engines. If you need to allow specific external origins to frame you, that is precisely the job of CSP frame-ancestors, below.

X-Frame-Options has real limitations. It carries a single policy per page, cannot express a list of allowed origins, and is evaluated inconsistently in nested-frame scenarios. But it is honored by essentially every browser in use, which is why it remains valuable as a baseline even though a newer, more expressive control now exists. The practical guidance most defenders follow is not “pick one” but “send both”: X-Frame-Options for maximum compatibility and frame-ancestors for correctness.


CSP frame-ancestors: the modern replacement

The frame-ancestors directive is part of Content-Security-Policy (CSP Level 2). It answers the same question as X-Frame-Optionswho may frame this page? — but with more precision and better-defined behavior. It is delivered inside the Content-Security-Policy header:

Content-Security-Policy: frame-ancestors 'none';
Content-Security-Policy: frame-ancestors 'self';
Content-Security-Policy: frame-ancestors 'self' https://partner.example.com;

Two behaviors matter. First, frame-ancestors is not governed by default-src; if you rely on default-src for other directives, you must still declare frame-ancestors explicitly, or framing is unrestricted. Second, when a page sends both X-Frame-Options and a CSP frame-ancestors directive, modern browsers give frame-ancestors precedence and ignore X-Frame-Options. That is why the two never conflict in practice — the modern control wins where it is understood, and the legacy header covers the vanishing few clients that do not understand CSP.

frame-ancestors rides on the same header that carries a site’s whole content policy, and that header is scarce: the census finds a Content-Security-Policy on only 8.0% of the web. The broader story of CSP adoption — and why 92% of sites ship without one — is measured in Content-Security-Policy Adoption in 2026: The 8.0% Web.


The census reality: how exposed the web is

Run the frame-protection question across the whole measured internet and the picture is stark. Across the 284,598,752 domains graded on their overall web-security posture in the August 2026 census, browser-side defenses are the exception, not the rule.

Only 8.0% of the web sets any Content-Security-Policy at all — and frame-ancestors is a directive inside that header, so the modern clickjacking defense cannot be present on the other 92% of sites that ship no CSP. X-Frame-Options extends coverage somewhat, since a site can send it without a full CSP, but it too remains a minority header across the census.

The isolation headers that harden framing and cross-origin interaction further — Cross-Origin-Opener-Policy, Cross-Origin-Embedder-Policy, and Cross-Origin-Resource-Policy — appear on under 1% of domains. That population is measured directly in the companion report The Isolation Headers: Why COOP, COEP and CORP Cover Less Than 1% of the Web. For the grading detail on each, see the COOP methodology and CORP methodology.

The thinness is not confined to framing. Only 20.1% of domains — 46,539,716 — deploy any HTTP Strict-Transport-Security, and the privacy-focused Referrer-Policy header is omitted by 91% of the web, quantified in Referrer-Policy: The Privacy Header 91% of the Web Forgot. The pattern repeats across every response header the census grades: the browser-side security layer is, for most of the internet, simply not configured. Clickjacking protection is one of the cheapest of these headers to add and one of the most consequential to omit.

The takeaway is not that most sites have been attacked — most have not. It is that most sites have left the door open, and closing it is a one-line change that the great majority have never made.


How to stop clickjacking

The fix is the same regardless of your stack: send an anti-framing header on every response. Best practice is to send both headers — X-Frame-Options for compatibility and CSP frame-ancestors for correctness — with matching intent. Use SAMEORIGIN / 'self' if your own app frames its own pages; use DENY / 'none' if nothing should ever frame the page.

nginx — add to your server (or location) block, and keep the always flag so the header is sent on error responses too:

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

Apache (with mod_headers enabled):

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

Cloudflare — no origin change needed. Use Rules → Transform Rules → Modify Response Header to add both headers, or set them in a Worker:

response.headers.set("X-Frame-Options", "SAMEORIGIN");
response.headers.set("Content-Security-Policy", "frame-ancestors 'self'");

Three practical notes:

  1. Choose the right strictness. If no legitimate site — not even yours — ever needs to frame the page, prefer DENY / frame-ancestors 'none'. Reserve SAMEORIGIN / 'self' for pages your own application genuinely embeds.
  2. Name partners explicitly, never wildcard. If an external partner must embed you, list their exact origin in frame-ancestors ('self' https://partner.example.com). Do not fall back to the obsolete ALLOW-FROM, and never open framing to all origins.
  3. Send it everywhere. A frame defense on the homepage but not on the “confirm” or “settings” endpoints protects nothing that matters. Set the header globally so every authenticated action is covered.

Then confirm it is actually being sent. A header present in your config but stripped by a proxy, a CDN, or a caching layer is no protection at all — which is why testing the live response, not the config file, is the only reliable check. If you want the whole browser-header layer set correctly in one pass rather than header by header, see how the fix works.


What this means

For business owners, clickjacking is the attack that turns your own logged-in customers into the weapon. A criminal does not need to breach your servers — they need only frame a page a customer is already authenticated to and steal a single click: an approval, a fund transfer confirmation, a permission grant. The exposure is highest exactly where a click is worth the most. Yet with only 8.0% of the web carrying a CSP, most businesses have never sent the header that makes the attack impossible. It is free, it is one line, and it protects your customers from being tricked in your name. Not sending it is a decision to stay framable.

For IT and security teams, frame protection is the lowest-effort, highest-certainty control on the header checklist. Unlike a full CSP — which can take iterations to tune without breaking legitimate scripts — frame-ancestors 'self' plus X-Frame-Options: SAMEORIGIN is almost always safe to ship immediately, because very few applications are framed by anyone but themselves. Audit every authenticated action endpoint, not just the marketing pages; verify the header survives your CDN and reverse proxy; and treat a missing frame defense on any state-changing page as a finding, not a nice-to-have. The full set of response headers to standardize on is laid out in HTTP Security Headers: The Complete Checklist.


FAQ

What is clickjacking? Clickjacking is a UI-redress attack in which an attacker loads your legitimate web page invisibly inside a frame on a page they control, then tricks a visitor into clicking something on your site they never intended to click — often a sensitive, one-click action the visitor is authenticated to perform. The visitor sees the attacker’s decoy; their click passes through to your hidden page. Because the request is a real, authenticated action from a real browser, nothing looks abnormal on your server. The defense is a response header telling browsers who may frame your pages. The August 2026 census found only 8.0% of the web sets the Content-Security-Policy that carries the modern version of that control.

How does X-Frame-Options prevent clickjacking? X-Frame-Options tells the browser whether your page is allowed to be displayed inside a frame. With X-Frame-Options: DENY, the browser refuses to render the page in any frame; with SAMEORIGIN, it renders only when the framing page shares your origin. Because every clickjacking attack requires framing your page from an attacker-controlled site, forbidding cross-origin framing removes the precondition the attack depends on — the invisible overlay can no longer load your page at all. It is a single header, honored by essentially every browser, and it breaks nothing for sites that are not framed by third parties. You can check whether your domain sends it free at defaults.exposed.

Is X-Frame-Options deprecated? Not exactly — it is superseded, not removed. Modern browsers still honor X-Frame-Options: DENY and SAMEORIGIN, so the header remains useful for compatibility, especially for older clients. What is obsolete is its ALLOW-FROM value, which was poorly supported and is now ignored everywhere; its job is done by CSP frame-ancestors. When a page sends both X-Frame-Options and a frame-ancestors directive, modern browsers use frame-ancestors and ignore X-Frame-Options. The current best practice is therefore to send both: frame-ancestors for correct, expressive control and X-Frame-Options as a fallback for anything that does not understand CSP.

What is the difference between X-Frame-Options and CSP frame-ancestors? Both answer “who may frame this page?”, but frame-ancestors is the newer, more capable control. X-Frame-Options offers only two working modes — DENY and SAMEORIGIN — and cannot list allowed external origins. frame-ancestors, part of Content-Security-Policy Level 2, adds 'none' and 'self' equivalents and lets you name one or more specific origins that may frame you (frame-ancestors 'self' https://partner.example.com). It is not governed by default-src, so you must declare it explicitly. Where both are present, browsers give frame-ancestors precedence. The catch is reach: frame-ancestors lives inside the CSP header, and the census finds a CSP on just 8.0% of domains, so the modern defense is absent from most of the web.

Can I stop my site from being framed on every stack? Yes. The control is a response header, so it works identically whether you run nginx, Apache, IIS, a Node or Python app server, or sit behind Cloudflare. On nginx, add_header X-Frame-Options "SAMEORIGIN" always; plus a matching Content-Security-Policy "frame-ancestors 'self'". On Apache, the equivalent Header always set directives. On Cloudflare, a Transform Rule or a one-line Worker. The only real pitfall is scope: set the header globally so it covers every authenticated, state-changing endpoint — not just the homepage — and confirm a proxy or CDN is not stripping it before it reaches the browser.

Data to cite

See where your own domain stands

Frame protection is invisible until it is missing — and by then the click has already been stolen. The only way to know whether a browser will let a stranger frame your pages is to look at the headers your live site actually sends, not the config you believe is in place.

Check your domain free at defaults.exposed — it reads your live response headers and tells you instantly whether you send X-Frame-Options, whether a Content-Security-Policy with frame-ancestors is present, and where your browser-side defenses have gaps. Takes about 30 seconds. No account needed. If you want the whole header layer — frame protection, CSP, HSTS, and the rest — set correctly in one pass, see how the fix works.

Read the flagship census report: The State of Domain Security 2026 →

Related from this series: The Isolation Headers: Why COOP, COEP and CORP Cover Less Than 1% of the Web · Content-Security-Policy Adoption in 2026: The 8.0% Web · HTTP Security Headers: The Complete Checklist · Referrer-Policy: The Privacy Header 91% of the Web Forgot

Aggregate data only. Data stored and processed in the EU.


Data source: defaults.exposed August 2026 census, methodology v9, as of 2026-08-16. 432,127,908 domains scanned; 284,598,752 graded on overall web-security posture. All figures are counts or shares of graded domains. References: RFC 7034 (X-Frame-Options), Content Security Policy Level 2 (frame-ancestors).


How to cite this report

Press / blog: defaults.exposed (2026). What Is Clickjacking? X-Frame-Options and How to Stop It. defaults.exposed August 2026 Domain Security Census (432,127,908 domains scanned, asOf 2026-08-16). Retrieved from https://defaults.exposed/v9/articles/what-is-clickjacking-x-frame-options-and-how-to-stop-it

Academic: defaults.exposed. (2026, August 21). What Is Clickjacking? X-Frame-Options and How to Stop It. In defaults.exposed Domain Security Census: August 2026. https://defaults.exposed/v9/articles/what-is-clickjacking-x-frame-options-and-how-to-stop-it

In-line citation: (defaults.exposed, August 2026 Domain Security Census, n=284,598,752 graded domains)


About the defaults.exposed August 2026 Census

The defaults.exposed Domain Security Census is a recurring independent measurement of the public domain namespace. The August 2026 edition scanned 432,127,908 domains between 1–16 August 2026 and graded 284,598,752 of them on overall web-security posture using methodology v9. Scans are conducted from EU infrastructure. No individual domain, registrant, or business is named in any report. All figures are aggregate distributions. Data is stored and processed within the EU.

Methodology: defaults.exposed/v9/methodology Full census report: defaults.exposed/en/articles/the-state-of-domain-security-2026

Data sourced from the August 2026 grading methodology (v9) — 34 checks, 376 million domains. Browse the census statistics or the Census Explorer, or see all August 2026 research →