Skip to main content
interlace
Plugin: browser-securityRules

no-clickjacking

Detects clickjacking vulnerabilities and missing frame protections

⚠️ Deprecated. This rule is deprecated and no longer in any preset. Use express-security/require-helmet, which sets X-Frame-Options and a frame-ancestors policy for every response through helmet. The rule is still exported and still works when enabled explicitly, until the next major removes it.

CWE: CWE-1021
OWASP: Clickjacking Defense Cheat Sheet

Detects clickjacking vulnerabilities and missing frame protections. This rule is part of eslint-plugin-browser-security.

Quick Summary

AspectDetails
CWE ReferenceCWE-1021 (Improper Restriction of Rendered UI Layers)
SeverityMedium (CVSS 6.1)
Auto-Fix❌ No
CategorySecurity

Vulnerability and Risk

Vulnerability: Clickjacking (UI Redressing) occurs when an attacker uses transparent or opaque layers (like <iframe>) to trick a user into clicking on a button or link on another page when they intended to click on the top level page.

Risk: Attackers can hijack clicks to perform sensitive actions on behalf of the user, such as transferring funds, changing settings, deleting accounts, or liking a social media post, without the user's knowledge.

Rule Details

Clickjacking tricks users into clicking on invisible or disguised elements by overlaying them with transparent frames. Attackers can:

  • Trick users into performing unintended actions
  • Steal clicks and credentials
  • Perform unauthorized transactions
  • Bypass CSRF protections

What the rule reports

FindingWhen
missingFrameBustingA file that builds a document shell (<html> / <head> / <body> in JSX) and neither declares frame protection nor frame-busts. Only with requireFrameBusting (default true).
weakFrameProtectionA declaration that does not forbid framing, written anywhere: an X-Frame-Options value other than DENY / SAMEORIGIN (ALLOWALL, ALLOW-FROM …) in a header slot, or a Content-Security-Policy with no frame-ancestors (or frame-ancestors *). Not reported when the same file declares real protection, or when the shell finding above already fired.
unsafeIframeUsageAn <iframe> whose src origin is not in trustedSources — an allowlist of iframe source origins, compared by origin, never by substring. 'self' / 'same-origin' accept relative URLs.
transparentFrameOverlayAn invisible overlay in CSS — opacity: 0, visibility: hidden, a negative z-index — when detectTransparentOverlays is on. display: none is not an overlay.
frameManipulationNavigating top.location / window.top outside a frame-busting guard. if (top != self) top.location = self.location is the remediation and is not reported. Only an assignment counts: reading top.location ('framed at ' + top.location) navigates nothing.

Why This Matters

IssueImpactSolution
🖱️ Click TheftUnauthorized actionsUse X-Frame-Options header
💳 FraudFinancial lossImplement CSP frame-ancestors
🔓 Account CompromiseData theftAdd frame-busting code

Examples

❌ Incorrect

// A document shell with no frame protection (missingFrameBusting)
export default function RootLayout({ children }) {
  return <html><body>{children}</body></html>;
}

// Allowing framing from any origin (weakFrameProtection)
res.setHeader('X-Frame-Options', 'ALLOWALL'); // Insecure!

// A frame from an origin not in trustedSources (unsafeIframeUsage),
// made invisible on top of the page (transparentFrameOverlay)
<iframe
  src="https://target.com/transfer"
  style="opacity: 0; position: absolute; top: 0; left: 0;"
/>

// Missing CSP frame-ancestors (weakFrameProtection)
const csp = "default-src 'self'"; // No frame protection!

✅ Correct

<iframe src="/local-content.html"></iframe>

res.setHeader('X-Frame-Options', 'DENY');
const csp = "default-src 'self'; frame-ancestors 'none'";

if (top !== self) {
  top.location = self.location; // frame-busting: the remediation
}

Configuration

{
  rules: {
    'browser-security/no-clickjacking': ['error', {
      trustedSources: ['self', 'https://trusted.com'],
      requireFrameBusting: true,
      detectTransparentOverlays: true
    }]
  }
}

Options

OptionTypeDefaultDescription
trustedSourcesstring[]["self","same-origin"]Iframe src origins treated as safe (self / same-origin accept relative URLs)
requireFrameBustingbooleantrueRequire frame-busting code in addition to headers
detectTransparentOverlaysbooleantrueReport transparent overlays positioned over clickable elements
trustedAnnotationsstring[][]Additional JSDoc annotations to consider as safe markers
strictModebooleanfalseDisable all false positive detection (strict mode)

Error Message Format

🔒 CWE-1021 OWASP:A05-Misconfig CVSS:6.1 | Clickjacking Vulnerability | MEDIUM [SOC2,PCI-DSS]
   Fix: Add X-Frame-Options: DENY or CSP frame-ancestors | https://cheatsheetseries.owasp.org/...

Known False Negatives

The following patterns are not detected due to static analysis limitations:

Values from Variables

Why: Values stored in variables are not traced.

// ❌ NOT DETECTED - Value from variable
const value = userInput;
dangerousOperation(value);

Mitigation: Validate all user inputs.

Wrapper Functions

Why: Custom wrappers not recognized.

// ❌ NOT DETECTED - Wrapper
myWrapper(userInput); // Uses dangerous API internally

Mitigation: Apply rule to wrapper implementations.

Dynamic Invocation

Why: Dynamic calls not analyzed.

// ❌ NOT DETECTED - Dynamic
obj[method](userInput);

Mitigation: Avoid dynamic method invocation.

Further Reading

Use this rule

npm install -D oxlint-plugin-browser-security
.oxlintrc.json
{  "jsPlugins": ["oxlint-plugin-browser-security"],  "rules": {    "browser-security/no-clickjacking": "error"  }}
vite.config.ts
import { defineConfig } from 'vite-plus';export default defineConfig({  lint: {    jsPlugins: ['oxlint-plugin-browser-security'],    rules: {      'browser-security/no-clickjacking': 'error',    },  },});

oxlint-plugin-browser-security re-exports eslint-plugin-browser-security/oxlint: the same rules under the same IDs, and no ESLint install. Why oxlint.

Did this rule catch something? Star the repo to get new CWE coverage as we ship it — or follow the AI-code-security benchmarks behind these rules.