The short answer

Tell browsers who may put your pages in a frame. The modern way is a CSP directive; the older header still helps older browsers:

Content-Security-Policy: frame-ancestors 'self'
X-Frame-Options: SAMEORIGIN

Use frame-ancestors 'none' (or X-Frame-Options: DENY) if your pages are never framed, even by your own site.

How the attack works

A clickjacking attack with and without frame protection Top, no protection: an attacker page shows a Win a prize button. Underneath, an invisible frame loads your account page, where the visitor is signed in, positioned so the Delete account button sits under the prize button. The visitor clicks and the action happens on your site. Bottom, with frame-ancestors self: the browser refuses to show your page inside the attacker’s frame, so the click hits nothing. Page can be framed Attacker page “Click to win a prize” Invisible frame Your page, opacity 0 Visitor is signed in Visitor clicks Thinks it is the prize Action on your site Settings changed, payment approved Your page performs the action The visitor never sees your site frame-ancestors 'self' Attacker page “Click to win a prize” Browser checks Who may frame this page? Frame refused Your page not rendered Click does nothing No action taken Only your own site can frame the page Works for every page that sends it A clickjacking attack with and without frame protection Top, no protection: an attacker page shows a Win a prize button. Underneath, an invisible frame loads your account page, where the visitor is signed in, positioned so the Delete account button sits under the prize button. The visitor clicks and the action happens on your site. Bottom, with frame-ancestors self: the browser refuses to show your page inside the attacker’s frame, so the click hits nothing. Page can be framed Attacker page “Click to win a prize” Invisible frame Your page, opacity 0 Visitor is signed in Visitor clicks Thinks it is the prize Action on your site Settings changed, payment approved Your page performs the action The visitor never sees your site frame-ancestors 'self' Attacker page “Click to win a prize” Browser checks Who may frame this page? Frame refused Your page not rendered Click does nothing No action taken Only your own site can frame the page Works for every page that sends it
Clickjacking needs your page to load inside someone else’s frame. One header tells the browser not to allow that.

How DNS Panopticon detects it

Security Posture reads your homepage’s Content-Security-Policy and X-Frame-Options headers. Browsers ignore X-Frame-Options when CSP frame-ancestors is present, so the check does the same. The result appears on the Website Application Security card.

FindingSeverityWhen it appears
Page can be framed by other sitesMediumNo frame-ancestors directive and no X-Frame-Options of DENY or SAMEORIGIN, or a frame-ancestors list that lets any site in (for example * or https:).
Framing by other sites is blockedPassframe-ancestors names specific sources, or X-Frame-Options is DENY or SAMEORIGIN.

How to check it yourself

CommandWhat to look for
curl -sI https://example.comA content-security-policy header containing frame-ancestors, or an x-frame-options header.

To test in a browser, save a local HTML file containing <iframe src="https://example.com/"></iframe> and open it. If your page appears, it can be framed. If protection is on, the frame stays empty and the console explains why.

Why it matters

  • Actions while signed in. Anything one or two clicks can do, such as changing an email address, approving a payment, enabling a webcam permission or following an account, can be triggered from another site.
  • Gets past CSRF tokens. The request really does come from the visitor’s browser on your site, so CSRF tokens alone do not stop it. SameSite=Lax or Strict session cookies help, because the browser leaves them out of a cross-site frame, but they do not cover same-site framing or every variant, so they do not replace frame-ancestors.
  • Cheap to block. One header on every response protects every page.

How to fix it

  1. Decide who may frame you. Usually nobody, or only your own site. If a partner or your own app on another domain embeds pages, list it: frame-ancestors 'self' https://partner.example.net.
  2. Send frame-ancestors in your Content-Security-Policy. If you have no CSP yet, a policy containing only frame-ancestors is fine.
  3. Also send X-Frame-Options (DENY or SAMEORIGIN) for older browsers. It cannot list other sites; ALLOW-FROM is obsolete and ignored by current browsers.
  4. Apply it everywhere, not just the homepage: account, settings and checkout pages matter most.
PlatformSetting
nginxadd_header Content-Security-Policy "frame-ancestors 'self'" always;
ApacheHeader always set Content-Security-Policy "frame-ancestors 'self'" (needs mod_headers)
IISIn web.config, under system.webServer/httpProtocol/customHeaders: <add name="Content-Security-Policy" value="frame-ancestors 'self'" />
CloudflareRules → Transform Rules → Modify Response Header, set the header on all requests
NetlifyIn _headers: a /* line, then Content-Security-Policy: frame-ancestors 'self' indented below it
Application codeMiddleware such as Helmet (Express) or the response headers settings of your framework

Set X-Frame-Options the same way with the value SAMEORIGIN. If you already send a Content-Security-Policy, add frame-ancestors to it rather than sending a second header. Many platforms, such as WordPress admin pages, already send SAMEORIGIN for their own screens.

FAQ

Should I use X-Frame-Options or frame-ancestors?

Both. frame-ancestors is the standard, supports lists of sites and wins when both are present. X-Frame-Options covers older browsers.

Our pages are embedded in a partner’s site. What now?

List the partner in frame-ancestors, for example frame-ancestors 'self' https://portal.partner.example. Every other site stays blocked.

Can I set frame-ancestors in a meta tag?

No. Browsers ignore frame-ancestors in a meta tag; it must be sent as an HTTP header.

Does this stop my own site from using iframes?

No. frame-ancestors controls who may frame your page. Which pages your page may frame is controlled by the separate frame-src directive.

Sources and further reading