Application Security
Clickjacking
UI Redressing
Security Headers
X-Frame-Options
+3 more

Clickjacking Attack Explained: Prevention, Examples, and Security Guide

SCRs Team
May 3, 2026
11 min read
Share

Clickjacking Is Quiet, Which Is Why It Gets Missed

Clickjacking rarely looks dramatic in a backlog or security report. There is no shell, no SQL dump, no stack trace. The application is simply willing to be framed, and the attacker lets the victim do the rest.

That makes it easy for teams to underestimate. In practice, though, any authenticated page with meaningful one-click actions can become useful to an attacker if it can be embedded and visually manipulated.

Clickjacking is a UI redressing attack where a malicious page loads your site inside a hidden or disguised iframe and tricks the user into clicking something they never intended to click.

Typical outcomes include:

  • Changing account settings
  • Approving sensitive actions
  • Starting payments or wire transfers
  • Granting OAuth permissions
  • Enabling camera or microphone access
Attack GoalExample Impact
Account takeover supportUser approves security-setting changes
Payment fraudUser clicks a hidden transfer confirmation button
OAuth consent abuseUser authorizes a malicious third-party app
Internal tool abuseAdmin clicks destructive buttons in hidden panels

Key point: Clickjacking is not about stealing cookies directly. It abuses the browser's normal rendering behavior and the victim's valid session.


How a Clickjacking Attack Works

The attacker hosts a page that looks harmless, such as a video player or giveaway form, then overlays or hides a live iframe from the target application behind bait content.

Simplified Attack Pattern

<style>
  iframe {
    position: absolute;
    top: 0;
    left: 0;
    width: 800px;
    height: 600px;
    opacity: 0.01;
    z-index: 2;
  }

  .fake-button {
    position: absolute;
    top: 220px;
    left: 260px;
    z-index: 1;
  }
</style>

<button class="fake-button">Play Video</button>
<iframe src="https://target.example/account/delete"></iframe>

The user thinks they are clicking the visible button. In reality, the click lands on the framed target page.


Why Clickjacking Still Matters in 2026

Teams often assume modern SPAs are immune. They are not. If an authenticated page can be framed and exposes meaningful user actions, clickjacking still works.

Common high-risk targets:

  • Billing pages
  • Account recovery settings
  • Admin dashboards
  • OAuth consent screens
  • One-click purchase flows
  • Internal enterprise tools

Vulnerability 1: Missing Frame Protections

If a page returns no frame restrictions, any origin may embed it.

Vulnerable Express Example

app.get('/settings', (req, res) => {
  res.send(renderSettingsPage());
});

Safer Response Headers

app.use((req, res, next) => {
  res.setHeader('X-Frame-Options', 'DENY');
  res.setHeader('Content-Security-Policy', "frame-ancestors 'none'");
  next();
});

Use both when practical. frame-ancestors is the modern control. X-Frame-Options provides older browser coverage.


Vulnerability 2: Allowing Framing for Entire Applications

Some teams allow framing globally because one embedded widget or partner integration needs it.

That broad exception creates unnecessary exposure for:

  • profile pages
  • payment flows
  • admin actions
  • consent screens

Better Approach

  • Allow framing only on the exact pages that need it.
  • Put embeddable widgets on separate origins or isolated routes.
  • Deny framing everywhere else.

Vulnerability 3: Relying Only on JavaScript Frame-Busting

Legacy code often tries this:

if (window.top !== window.self) {
  window.top.location = window.self.location;
}

That is not a reliable defense. Browser behavior, sandboxing rules, and CSP interactions make client-side frame-busting weaker than response headers.

Treat JavaScript frame-busting as optional defense-in-depth, not the primary control.


An attacker frames a legitimate OAuth authorization page and places a fake "Claim reward" button over the real "Allow" button.

If the user is already signed in to the identity provider, one click may grant a malicious app access to:

  • profile data
  • email address
  • cloud storage
  • calendar access

This is why identity flows also need frame protection.


How to Prevent Clickjacking in Next.js

Middleware Example

import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(_request: NextRequest) {
  const response = NextResponse.next();
  response.headers.set('X-Frame-Options', 'DENY');
  response.headers.set('Content-Security-Policy', "frame-ancestors 'none'");
  return response;
}

If some routes must be embeddable, carve them out explicitly instead of weakening the policy for the whole site.


Testing for Clickjacking

1. Manual Framing Test

Create a local HTML page that embeds the target route in an iframe. If the page renders, the route may be exposed.

2. Header Check

curl -I https://target.example/settings

Look for:

  • X-Frame-Options: DENY or SAMEORIGIN
  • Content-Security-Policy: frame-ancestors ...

3. High-Risk Route Review

Check all pages that:

  • change state
  • approve permissions
  • manage money
  • alter security settings

Clickjacking Hardening Checklist

  • Set Content-Security-Policy: frame-ancestors 'none' or a tight allowlist
  • Add X-Frame-Options for legacy browser coverage
  • Do not allow framing across the whole app for one integration
  • Isolate embeddable widgets on separate routes or origins
  • Review OAuth, billing, and admin pages first
  • Test framing on sensitive routes during security reviews

Final Takeaway

Clickjacking is one of the clearest examples of a "simple" bug with real operational impact. No exploit chain is required if the browser is willing to render the page and the user is already signed in. The cleanest defense is also the simplest one: decide which routes may be framed, and deny it everywhere else by default.

Advertisement