Safeguard
Vulnerability Analysis

What is Clickjacking

Clickjacking tricks users into clicking hidden UI via invisible iframes. Learn how it works, real incidents, key CVEs, and how to defend against it.

Nayan Dey
Security Researcher
6 min read

Clickjacking is a UI-redressing attack that tricks a user into clicking something other than what they perceive, typically by loading a target page in an invisible or disguised iframe layered beneath decoy content. The technique was first publicly named in 2008 by researchers Robert "RSnake" Hansen and Jeremiah Grossman, who built a proof of concept that hijacked a victim's webcam and microphone through Adobe Flash Player's settings manager — a demo serious enough that Adobe asked them to delay the talk. Attackers overlay a transparent iframe pointing at a sensitive action (changing account settings, approving an OAuth grant, enabling a device permission, authorizing a funds transfer) underneath a fake button, so a single click the victim believes is harmless actually fires against the hidden page. The vulnerability class is tracked today as CWE-1021, "Improper Restriction of Rendered UI Layers or Frames." It remains cheap to exploit, hard for end users to notice, and still shows up routinely in web application penetration test findings and bug bounty reports in 2026.

How does a clickjacking attack actually work?

A clickjacking attack works by stacking a legitimate, framed target page underneath an attacker-controlled decoy page and manipulating CSS opacity, z-index, and positioning so the victim only sees the decoy. The attacker sets the target site's URL as the src of an <iframe>, sets its opacity to near zero (or uses pointer-events and precise pixel offsets), and positions it exactly over a button on their own page — commonly labeled with bait like "Claim Your Prize" or "Continue." When the victim clicks the visible decoy button, the click actually lands on the invisible iframe's control underneath it: a "Delete Account" button, a "Grant Access" OAuth consent screen, or a router's "Enable Remote Administration" toggle. Variants extend this further. Cursorjacking, described by researcher Marcus Niemietz around 2012, spoofs the visual cursor position using custom CSS cursors so the click lands several pixels away from where the user thinks they're clicking. Drag-and-drop clickjacking and scroll-jacking apply the same layering trick to dragstart/drop events and scroll listeners instead of clicks.

What real-world incidents show clickjacking's actual impact?

Clickjacking has caused concrete, large-scale incidents since at least 2009, when a self-propagating Twitter worm used a hidden button labeled "Don't Click" that, once clicked, force-posted the same malicious tweet to the victim's followers, spreading to thousands of accounts within hours. In 2010, Facebook saw a wave of "likejacking" scams — fake "Free iPad" and "100 Like" pages that invisibly framed Facebook's Like button under a decoy play or download button, generating hundreds of thousands of forced Likes used to push scam links and fake antivirus downloads. Around 2012, independent researchers (including Egor Homakov) demonstrated OAuth clickjacking against major identity providers: an invisible "Allow" button on a third-party app's consent screen could be clicked without the victim ever seeing the permissions being granted, silently linking an attacker's app to the victim's account. Home router vendors have repeatedly shipped clickjackable admin panels lacking frame-busting headers, letting an attacker who lures an admin to a malicious page silently flip settings like remote management or DNS.

Why do CVE databases still list new clickjacking findings every year?

CVE databases still list new clickjacking findings every year because the fix is a single response header that many applications simply never set. A search of the National Vulnerability Database for "clickjacking" returns well over 400 entries spanning routers, CMS admin panels, IoT dashboards, monitoring tools, and enterprise SaaS login pages — the vast majority scored as low-to-medium severity but still exploitable for account takeover or configuration tampering when combined with social engineering. Grafana, phpMyAdmin, and multiple router firmware families have each had dedicated advisories filed specifically for missing X-Frame-Options or Content-Security-Policy: frame-ancestors directives on sensitive administrative or authentication pages. The pattern repeats because clickjacking protection is a configuration control, not a code-level input validation fix, so it's easy for a new microservice, a new admin route, or a third-party embedded widget to launch without inheriting the header a security team assumed was set globally.

How do X-Frame-Options and CSP frame-ancestors stop it?

X-Frame-Options and the CSP frame-ancestors directive stop clickjacking by telling the browser to refuse to render the page inside a frame at all, which removes the attacker's ability to stack it under a decoy. Setting X-Frame-Options: DENY blocks all framing; SAMEORIGIN allows framing only by pages on the same origin, which covers most legitimate use cases like internal dashboards. The newer and more flexible control, Content-Security-Policy: frame-ancestors 'self' (or an explicit allow-list of trusted origins), does the same job and is the W3C-recommended approach because CSP supports granular origin lists that X-Frame-Options cannot express. Both headers must be present on every response that renders sensitive state-changing UI — login forms, account settings, payment flows, admin consoles, OAuth consent screens — not just the homepage. A common gap: teams set the header at the reverse proxy or CDN layer for the main app but miss it on a separately deployed admin subdomain, an embedded support widget, or a legacy service still running behind the same domain.

How can security teams find clickjacking gaps before attackers do?

Security teams find clickjacking gaps before attackers do by combining automated header scanning across every live endpoint with manual verification of state-changing pages, because a missing header on a marketing page is noise but a missing header on an authenticated settings page is exploitable. OWASP's Web Security Testing Guide (WSTG-CLNT-09) lays out the manual test: build a local HTML page with a full-page iframe pointing at the target and an opacity of near-zero, then confirm whether the target renders. At scale, this means enumerating every subdomain and route an organization owns — including those spun up by shadow IT, marketing tooling, or forgotten staging environments — and checking response headers programmatically rather than relying on a single pen test snapshot taken once a year. Static header checks alone also miss context: a page can carry frame-ancestors 'self' yet still be reachable and exploitable if a same-origin page embeds attacker-influenced content, so header presence has to be correlated with what the page actually does and who can reach it.

How Safeguard Helps

Safeguard helps security teams close clickjacking gaps by mapping which internet-facing routes actually carry sensitive, state-changing functionality and cross-referencing that against real request paths, so reachability analysis flags missing frame-ancestors or X-Frame-Options headers on the endpoints that matter most rather than burying teams in low-priority findings across static pages. Griffin AI triages these findings in context — distinguishing a clickjackable marketing page from a clickjackable admin console or OAuth consent screen — and can generate an auto-fix PR that adds the correct CSP directive or security header at the framework or proxy config layer, cutting remediation from a ticket-and-wait cycle to a reviewable diff. Continuous SBOM generation and ingest keep the asset inventory current as new services, subdomains, and embedded widgets ship, so newly deployed routes inherit the same scrutiny instead of becoming the next forgotten admin panel a pen tester finds a year later.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.