Interlace ESLint
ESLint Interlace
Secure CodingRules

no-clickjacking

Detects clickjacking vulnerabilities and missing frame protections. This rule is part of [`eslint-plugin-secure-coding`](https://www.npmjs.com/package/eslint-pl

Keywords: clickjacking, CWE-1021, iframe, X-Frame-Options, CSP, UI redressing

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

💼 This rule is set to error in the recommended config.

Quick Summary

AspectDetails
CWE ReferenceCWE-1021 (Improper Restriction of Rendered UI Layers)
SeverityMedium (CVSS 6.1)
Auto-Fix💡 Suggestions available
CategoryNetwork & Headers

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

Why This Matters

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

Examples

❌ Incorrect

// Missing X-Frame-Options header
app.get('/sensitive', (req, res) => {
  res.send('<html>Sensitive content</html>');
});

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

// Transparent iframe overlay
<iframe
  src="https://target.com/transfer"
  style="opacity: 0; position: absolute; top: 0; left: 0;"
/>

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

✅ Correct

// Set X-Frame-Options header
app.use((req, res, next) => {
  res.setHeader('X-Frame-Options', 'DENY');
  // Or for same-origin only:
  // res.setHeader('X-Frame-Options', 'SAMEORIGIN');
  next();
});

// Use CSP frame-ancestors (more flexible)
res.setHeader(
  'Content-Security-Policy',
  "frame-ancestors 'self' https://trusted.com",
);

// Frame-busting JavaScript (legacy fallback)
if (top !== self) {
  top.location = self.location;
}

// Use helmet middleware
import helmet from 'helmet';
app.use(helmet.frameguard({ action: 'deny' }));

Configuration

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

Options

OptionTypeDefaultDescription
trustedSourcesstring[]['self']Trusted iframe sources
requireFrameBustingbooleantrueRequire frame-busting code
detectTransparentOverlaysbooleantrueDetect transparent overlays

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

On this page