Missing Frame Ancestors Protection

ID

html.missing_clickjacking_protection

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Access Control

Language

Html

Tags

ASVS50:v3.4.6, CWE:1021, NIST.SP.800-53, OWASP:2025:A06, PCI-DSS:6.5.4, PCI-DSS:6.5.6

Description

This rule identifies HTML documents that lack the Content Security Policy (CSP) frame-ancestors directive in their meta tags. The frame-ancestors directive controls which parent pages can embed the current page in frames, iframes, or objects, providing critical protection against clickjacking and unauthorized framing attacks.

Rationale

Clickjacking (also known as UI redressing) is a serious attack where malicious sites embed your application in an invisible or disguised iframe, tricking users into performing unintended actions. Without proper frame-ancestors protection, applications are vulnerable to several attack vectors:

Clickjacking Attacks: Attackers overlay transparent iframes containing your application over fake UI elements. Users think they’re clicking on benign content but are actually interacting with your application (e.g., transferring funds, changing passwords, authorizing actions).

Credentials Harvesting: Malicious sites can frame your login page and use sophisticated techniques to steal credentials or session tokens as users authenticate.

Social Engineering: Attackers can embed portions of your application within deceptive contexts, manipulating users into performing sensitive operations under false pretenses.

Context Confusion: Users may not realize they’re interacting with your application when it’s embedded in an attacker’s site, reducing their security vigilance and making phishing more effective.

Unauthorized Embedding: Even without malicious intent, unauthorized framing can damage your brand, create support issues, and violate terms of service when your application is embedded in unexpected contexts.

The frame-ancestors directive in CSP is the modern, flexible replacement for the legacy X-Frame-Options header, providing more granular control over which origins can frame your content.

Consider the following scenario:

<!DOCTYPE html>
<html>
<head>
  <title>Banking Application</title>
  <!-- No CSP frame-ancestors directive -->
</head>
<body>
  <h1>Transfer Funds</h1>
  <form action="/transfer" method="POST">
    <input type="text" name="recipient" />
    <input type="number" name="amount" />
    <button type="submit">Transfer</button>
  </form>
</body>
</html>

Attacker’s malicious site exploiting the missing protection:

<!DOCTYPE html>
<html>
<head>
  <title>Free iPhone Giveaway!</title>
  <style>
    iframe {
      position: absolute;
      width: 500px;
      height: 500px;
      opacity: 0.0001; /* Nearly invisible */
      z-index: 2;
    }
    .fake-button {
      position: absolute;
      width: 200px;
      height: 50px;
      z-index: 1;
      background: green;
      color: white;
      font-size: 24px;
    }
  </style>
</head>
<body>
  <h1>Click here to claim your FREE iPhone!</h1>
  <button class="fake-button">CLAIM NOW</button>

  <!-- Victim's banking app embedded invisibly -->
  <iframe src="https://victim-bank.com/transfer?recipient=attacker&amount=1000"></iframe>
</body>
</html>

When users click the fake button, they unknowingly submit the fund transfer in the invisible iframe.

Remediation

Framing is controlled by HTTP response headers. Browsers ignore frame-ancestors when it is delivered in a <meta> tag, and X-Frame-Options cannot be set from a <meta> tag at all, so the protection has to be configured where the page is served:

Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
  • Use frame-ancestors 'none' (or 'self') for login pages, payment forms and account settings.

  • Use an explicit list of trusted origins only for pages meant to be embedded.

  • Never use frame-ancestors *.

  • Keep X-Frame-Options alongside the CSP directive for older browsers (DENY → 'none', SAMEORIGIN → 'self').

Most web frameworks set these headers by default or with one setting: Django’s XFrameOptionsMiddleware, Spring Security’s headers().frameOptions(), ASP.NET Core’s antiforgery X-Frame-Options, the helmet middleware for Express. For a static site, configure them in the web server or CDN.

The rule reports HTML documents served as written. Server-side templates (Django/Jinja, Thymeleaf, the mustache family, JSP/ERB) and bundler entry points (<script type="module" src="/src/main.tsx">) are not reported: the headers for those pages are set by the server that renders or serves them, which the HTML file cannot show. A <meta http-equiv="Content-Security-Policy" content="frame-ancestors …​"> tag also silences the rule, as a declaration of the intended policy, but it must be matched by the response header to take effect.

© 2026 Xygeni. All rights reserved