Auditing clickjacking and UI redressing: the user clicks your button on the attacker's page
Clickjacking works because the browser will happily render your real, authenticated page inside a frame on
someone else's site, and the user cannot tell. The attacker loads your page in a transparent or hidden iframe,
positions it under decoy content, and lures the user into clicking what looks like the attacker's button, when
the click actually lands on your page, taken with the user's own session. So any sensitive, state-changing
action that a single click can trigger, changing a setting, confirming a purchase, granting an approval,
connecting an account, is exposed if your page can be framed by another origin. The defense is to refuse
framing by untrusted origins, with a Content-Security-Policy frame-ancestors directive (and the older
X-Frame-Options as a fallback), and, for the highest-value actions, to not make them one-click blind: a
confirmation the overlay cannot fake. Related redressing tricks, drag-and-drop and keystroke capture, exploit
the same framing to steal input. The audit checks, for every sensitive page, whether it can be framed and
whether its state-changing actions are reachable by a single hidden click. You audit this by trying to frame
the real page from another origin and drive its actions.
When to use
- A web page performs authenticated, state-changing actions triggerable by a click (settings, purchase,
approval, connect, delete).
- The page may lack a
frame-ancestors CSP directive or X-Frame-Options, so another origin can frame it.
- A sensitive action may be one-click with no confirmation an overlay cannot hide.
Scope check
Audit clickjacking only on applications you own or are authorized to assess. Framing the real site to
demonstrate the attack uses a real authenticated session, so use test accounts and your own attacker-page test
harness and never trick a real user or act on an account that is not yours. If you can't name the
authorization, stop.
The loop
Establish which actions are sensitive and whether the page can be framed first. Inventory the
authenticated, state-changing actions on each page and name which are high-value (money, permissions, data
deletion, account connection). Then determine the intended framing policy: which origins, if any, may embed
the page. This is the false-positive killer: a page that refuses framing by untrusted origins via
frame-ancestors and whose highest-value actions require a confirmation an overlay cannot fake is not
clickjackable. Name the sensitive actions and the framing policy, then test framing.
Test whether the page can be framed. From an attacker-origin test page, load the target in an iframe and
confirm whether the browser renders it. Check for a frame-ancestors CSP directive and, as a fallback,
X-Frame-Options; confirm they name only trusted origins. A page that renders in an arbitrary origin's frame
is embeddable for a redress.
Map one-click state-changing actions. For each sensitive action, determine whether a single click
triggers it with no further step. A framed one-click action, positioned under a decoy, is taken the moment
the user clicks the decoy. Actions that change money, permissions, or data with one click are the priority
targets.
Test overlay and confirmation hiding. Simulate the attack: overlay the framed page with decoy content
and confirm whether the sensitive control can be positioned under an innocuous-looking click. Check whether
any confirmation step is one the overlay can hide or auto-satisfy, or a genuine barrier the attacker cannot
fake. A confirmation the frame can cover is not protection.
Check drag-and-drop and keystroke redressing. Beyond clicks, test whether framing enables dragging a
value into a field, or capturing keystrokes the user believes go to the attacker page, to fill a sensitive
form on the framed site. These redressing variants exploit the same missing framing protection.
Confirm and record. Confirm from an attacker-origin test page by framing the real page and driving a
sensitive action with a click aimed at a decoy, using a test account and your own harness, without tricking a
real user. Kill the lead if the page refuses framing by untrusted origins via frame-ancestors (with
X-Frame-Options fallback) and its high-value actions require a confirmation the overlay cannot fake. Record
the attacker page that frames the site, the unknowing state-changing click, and the missing framing
protection or unguarded one-click action.
Where UI-redressing trust leaks
- No frame-ancestors or X-Frame-Options. A page with no framing restriction renders inside any origin's
iframe, ready to be overlaid and redressed.
- Permissive framing policy. A
frame-ancestors or X-Frame-Options that allows broad or wrong origins lets
an attacker-controlled or compromised origin frame the page.
- One-click sensitive actions. A state-changing action a single click triggers is taken the instant the
user clicks a decoy positioned over it.
- Fakeable confirmations. A confirmation step the framed overlay can hide, cover, or auto-satisfy is not a
barrier to a redress.
- Input redressing. Framing that allows drag-and-drop or keystroke capture fills sensitive fields on the
real page with input the user meant for the decoy.
Worked example (a confirm and a kill)
Confirm. An account settings page lets a user connect an external account or change a security setting
with a single button click, and the page sends no frame-ancestors CSP directive and no X-Frame-Options. An
attacker-origin test page loads it in a transparent iframe under a decoy game, positions the connect button
under the decoy's "play" button, and a test user's click connects the account without their awareness.
Confirmed clickjacking of a sensitive one-click action via missing framing protection, high,
remediation = set frame-ancestors 'self' (and X-Frame-Options DENY or SAMEORIGIN as fallback) on sensitive
pages, and require a confirmation an overlay cannot fake for high-value actions.
Kill. Sensitive pages send frame-ancestors 'self' (with X-Frame-Options as a fallback) so no untrusted
origin can frame them, and the highest-value actions require a confirmation the overlay cannot hide or
auto-satisfy. An attacker-origin frame is refused by the browser, so no decoy overlay can steer a click.
Killed, kill_reason = "page refuses framing by untrusted origins via frame-ancestors and high-value
actions require a non-fakeable confirmation; no framed click reaches a sensitive action."
Rationalizations to reject
- "Who would frame our site." → Framing is a single iframe tag on any attacker page; the barrier is
frame-ancestors, not obscurity, and without it the page is embeddable by anyone.
- "We set X-Frame-Options." → Confirm it is actually sent on the sensitive pages and not overridden, and add
frame-ancestors since X-Frame-Options is the legacy fallback; a header set on some pages but not the
sensitive one still exposes it.
- "The action needs a confirmation." → Confirm the overlay cannot hide or auto-satisfy that confirmation; a
dialog the frame can cover or a checkbox the attacker pre-clicks is not a barrier.
- "It is behind login." → Clickjacking uses the victim's own logged-in session; being authenticated is the
precondition for the attack, not a defense.
- "CSP is for script." → CSP also governs framing via
frame-ancestors; the same header that constrains
script is where you refuse untrusted framers.
Executing this in practice
You need the sensitive, state-changing actions on each page, the framing headers each page sends
(frame-ancestors and X-Frame-Options), whether each sensitive action is one-click, and whether its
confirmation is fakeable under an overlay. From an attacker-origin test harness, try to frame each sensitive
page and drive its actions under a decoy. Reading the response headers shows the intended framing policy; a
sensitive action driven from a framed decoy on your harness shows whether it holds.
Related
auditing-third-party-script-and-sri-trust - the other front-end trust boundary set by response headers; CSP
carries both frame-ancestors here and the script allowlist there.
auditing-cors-and-cross-origin-trust - the cross-origin trust boundary framing sits within; both decide
what another origin may do with your authenticated context, one via requests, the other via a frame.
hunting-wallet-drainer-and-dapp-approval-abuse - a redressed dApp UI hides a signing prompt; UI redressing
and approval deception combine to get a user to authorize what they cannot see.
mapping-attack-surface - use it to enumerate the authenticated, state-changing pages that need framing
protection before testing each.
- FINDING-SCHEMA.md - source = the attacker page that frames or overlays the real
site, sink = the unknowing state-changing click, evidence = the missing framing protection or unguarded
one-click action.
1---2name: auditing-clickjacking-and-ui-redressing3description: Audit a web application for UI-redressing attacks where an attacker frames the real site and tricks a user into acting on it unknowingly: a sensitive page that can be embedded in an attacker's iframe because it lacks frame-ancestors or X-Frame-Options, a state-changing action reachable by a single click that an overlay or transparent frame steers, a drag-and-drop or keystroke redressing that captures input meant for the attacker page, and a confirmation step that a framed overlay hides. Covers web pages with authenticated, state-changing actions (settings changes, purchases, approvals, connect flows) that could be loaded inside a frame the user cannot see. Use when a sensitive action can be triggered by a click and the page can be framed by another origin, making framing the boundary. The attacker page that frames or overlays the real site is the source, the unknowing state-changing click is the sink, and the missing framing protection or unguarded one-click action is the bug.4license: MIT5---67# Auditing clickjacking and UI redressing: the user clicks your button on the attacker's page89Clickjacking works because the browser will happily render your real, authenticated page inside a frame on10someone else's site, and the user cannot tell. The attacker loads your page in a transparent or hidden iframe,11positions it under decoy content, and lures the user into clicking what looks like the attacker's button, when12the click actually lands on your page, taken with the user's own session. So any sensitive, state-changing13action that a single click can trigger, changing a setting, confirming a purchase, granting an approval,14connecting an account, is exposed if your page can be framed by another origin. The defense is to refuse15framing by untrusted origins, with a Content-Security-Policy `frame-ancestors` directive (and the older16X-Frame-Options as a fallback), and, for the highest-value actions, to not make them one-click blind: a17confirmation the overlay cannot fake. Related redressing tricks, drag-and-drop and keystroke capture, exploit18the same framing to steal input. The audit checks, for every sensitive page, whether it can be framed and19whether its state-changing actions are reachable by a single hidden click. You audit this by trying to frame20the real page from another origin and drive its actions.2122## When to use2324- A web page performs authenticated, state-changing actions triggerable by a click (settings, purchase,25 approval, connect, delete).26- The page may lack a `frame-ancestors` CSP directive or X-Frame-Options, so another origin can frame it.27- A sensitive action may be one-click with no confirmation an overlay cannot hide.2829## Scope check3031Audit clickjacking only on applications you own or are authorized to assess. Framing the real site to32demonstrate the attack uses a real authenticated session, so use test accounts and your own attacker-page test33harness and never trick a real user or act on an account that is not yours. If you can't name the34authorization, stop.3536## The loop37381. **Establish which actions are sensitive and whether the page can be framed first.** Inventory the39 authenticated, state-changing actions on each page and name which are high-value (money, permissions, data40 deletion, account connection). Then determine the intended framing policy: which origins, if any, may embed41 the page. This is the false-positive killer: a page that refuses framing by untrusted origins via42 `frame-ancestors` and whose highest-value actions require a confirmation an overlay cannot fake is not43 clickjackable. Name the sensitive actions and the framing policy, then test framing.44452. **Test whether the page can be framed.** From an attacker-origin test page, load the target in an iframe and46 confirm whether the browser renders it. Check for a `frame-ancestors` CSP directive and, as a fallback,47 X-Frame-Options; confirm they name only trusted origins. A page that renders in an arbitrary origin's frame48 is embeddable for a redress.49503. **Map one-click state-changing actions.** For each sensitive action, determine whether a single click51 triggers it with no further step. A framed one-click action, positioned under a decoy, is taken the moment52 the user clicks the decoy. Actions that change money, permissions, or data with one click are the priority53 targets.54554. **Test overlay and confirmation hiding.** Simulate the attack: overlay the framed page with decoy content56 and confirm whether the sensitive control can be positioned under an innocuous-looking click. Check whether57 any confirmation step is one the overlay can hide or auto-satisfy, or a genuine barrier the attacker cannot58 fake. A confirmation the frame can cover is not protection.59605. **Check drag-and-drop and keystroke redressing.** Beyond clicks, test whether framing enables dragging a61 value into a field, or capturing keystrokes the user believes go to the attacker page, to fill a sensitive62 form on the framed site. These redressing variants exploit the same missing framing protection.63646. **Confirm and record.** Confirm from an attacker-origin test page by framing the real page and driving a65 sensitive action with a click aimed at a decoy, using a test account and your own harness, without tricking a66 real user. Kill the lead if the page refuses framing by untrusted origins via `frame-ancestors` (with67 X-Frame-Options fallback) and its high-value actions require a confirmation the overlay cannot fake. Record68 the attacker page that frames the site, the unknowing state-changing click, and the missing framing69 protection or unguarded one-click action.7071## Where UI-redressing trust leaks7273- **No frame-ancestors or X-Frame-Options.** A page with no framing restriction renders inside any origin's74 iframe, ready to be overlaid and redressed.75- **Permissive framing policy.** A `frame-ancestors` or X-Frame-Options that allows broad or wrong origins lets76 an attacker-controlled or compromised origin frame the page.77- **One-click sensitive actions.** A state-changing action a single click triggers is taken the instant the78 user clicks a decoy positioned over it.79- **Fakeable confirmations.** A confirmation step the framed overlay can hide, cover, or auto-satisfy is not a80 barrier to a redress.81- **Input redressing.** Framing that allows drag-and-drop or keystroke capture fills sensitive fields on the82 real page with input the user meant for the decoy.8384## Worked example (a confirm and a kill)8586> **Confirm.** An account settings page lets a user connect an external account or change a security setting87> with a single button click, and the page sends no `frame-ancestors` CSP directive and no X-Frame-Options. An88> attacker-origin test page loads it in a transparent iframe under a decoy game, positions the connect button89> under the decoy's "play" button, and a test user's click connects the account without their awareness.90> **Confirmed** clickjacking of a sensitive one-click action via missing framing protection, `high`,91> remediation = set `frame-ancestors 'self'` (and X-Frame-Options DENY or SAMEORIGIN as fallback) on sensitive92> pages, and require a confirmation an overlay cannot fake for high-value actions.93>94> **Kill.** Sensitive pages send `frame-ancestors 'self'` (with X-Frame-Options as a fallback) so no untrusted95> origin can frame them, and the highest-value actions require a confirmation the overlay cannot hide or96> auto-satisfy. An attacker-origin frame is refused by the browser, so no decoy overlay can steer a click.97> **Killed**, `kill_reason` = "page refuses framing by untrusted origins via frame-ancestors and high-value98> actions require a non-fakeable confirmation; no framed click reaches a sensitive action."99100## Rationalizations to reject101102- *"Who would frame our site."* → Framing is a single iframe tag on any attacker page; the barrier is103 `frame-ancestors`, not obscurity, and without it the page is embeddable by anyone.104- *"We set X-Frame-Options."* → Confirm it is actually sent on the sensitive pages and not overridden, and add105 `frame-ancestors` since X-Frame-Options is the legacy fallback; a header set on some pages but not the106 sensitive one still exposes it.107- *"The action needs a confirmation."* → Confirm the overlay cannot hide or auto-satisfy that confirmation; a108 dialog the frame can cover or a checkbox the attacker pre-clicks is not a barrier.109- *"It is behind login."* → Clickjacking uses the victim's own logged-in session; being authenticated is the110 precondition for the attack, not a defense.111- *"CSP is for script."* → CSP also governs framing via `frame-ancestors`; the same header that constrains112 script is where you refuse untrusted framers.113114## Executing this in practice115116You need the sensitive, state-changing actions on each page, the framing headers each page sends117(`frame-ancestors` and X-Frame-Options), whether each sensitive action is one-click, and whether its118confirmation is fakeable under an overlay. From an attacker-origin test harness, try to frame each sensitive119page and drive its actions under a decoy. Reading the response headers shows the intended framing policy; a120sensitive action driven from a framed decoy on your harness shows whether it holds.121122## Related123124- `auditing-third-party-script-and-sri-trust` - the other front-end trust boundary set by response headers; CSP125 carries both `frame-ancestors` here and the script allowlist there.126- `auditing-cors-and-cross-origin-trust` - the cross-origin trust boundary framing sits within; both decide127 what another origin may do with your authenticated context, one via requests, the other via a frame.128- `hunting-wallet-drainer-and-dapp-approval-abuse` - a redressed dApp UI hides a signing prompt; UI redressing129 and approval deception combine to get a user to authorize what they cannot see.130- `mapping-attack-surface` - use it to enumerate the authenticated, state-changing pages that need framing131 protection before testing each.132- [FINDING-SCHEMA.md](../../FINDING-SCHEMA.md) - source = the attacker page that frames or overlays the real133 site, sink = the unknowing state-changing click, evidence = the missing framing protection or unguarded134 one-click action.