Back to Technical Mode

Clickjacking

An attacker overlays a transparent iframe of your site on top of their own deceptive page, positioning a sensitive button (like 'Delete Account' or 'Authorize Payment') exactly under something the victim is enticed to click — the victim's real click is captured by your site, not the attacker's.

The victim genuinely clicks on your real page — their session, their cookies, their authenticated click — they just don't realize which page they're clicking on because of the invisible overlay
This is entirely a browser-rendering-layer attack — no code on your site needs to be buggy for it to work, as long as your site can be framed at all
The fix is telling the browser your page must never be rendered inside a frame (or only inside frames from origins you trust) — content, not behavior, is what's being defended
The X-Frame-Options header is the older, simpler control; the frame-ancestors directive of Content-Security-Policy is the modern, more flexible replacement and takes precedence where both are supported

Want this flow explained in detail as it plays?

GET/account/delete

Headers

Host:app.flowground.dev

Body

Loading...

Quick-Insert Payloads

Defense in depth

  • Send X-Frame-Options: DENY (or SAMEORIGIN if legitimate same-site framing is needed) on every response for pages that perform sensitive actions
  • Set Content-Security-Policy: frame-ancestors 'none' (or a specific allowlist of trusted origins) as the modern, more expressive replacement/complement to X-Frame-Options
  • For the highest-risk actions (account deletion, fund transfers), consider requiring a re-confirmation step (re-entering a password, a distinct confirmation dialog) that's harder to blindly click through even if framing somehow succeeds

Vulnerable vs. Fixed

app.get("/account/delete", requireAuth, (req, res) => {
  res.render("confirm-delete"); // no framing protection headers set at all — can be embedded in any iframe
});