Clickjacking: block other sites from loading yours in a hidden frame
A one-line frame-ancestors directive tells browsers no other site may embed your pages
The threat
Our scanner saw your responses come back with neither a Content-Security-Policy: frame-ancestors directive nor an X-Frame-Options header. With both missing, any other website is free to load your pages inside an <iframe>. That sounds harmless until you see how it gets used.
This is clickjackingclickjackingAttackAn attack that invisibly frames your real site over a decoy, so victims click genuine buttons without knowing. Blocked by frame-ancestors or X-Frame-Options.. A malicious page stacks your real, logged-in site in a transparent frame directly over its own decoy buttons. The visitor believes they are clicking something on the attacker’s page (a “play” button, a “claim prize” link), but the click actually lands on a live control of yours: “confirm order”, “delete”, “authorize”, “change email”. They never see your site, and they never meant to click it. Two headers make the browser refuse to be framed at all, which ends the attack before it starts.
The exact fix
Tell browsers no one may frame you. The modern control is the CSPCSPHTTP headerContent-Security-Policy: a response header that whitelists exactly which scripts, styles, images and connections a page may use, so an injected payload simply has no permission to run. frame-ancestorsframe-ancestorsCSP directiveThe CSP directive deciding who may embed your page in an <iframe>. Set to 'none' to make clickjacking impossible. directive; X-Frame-Options is the legacy fallback for older browsers. Ship both. On Netlify, add them in netlify.toml:
# netlify.toml
[[headers]]
for = "/*"
[headers.values]
Content-Security-Policy = "frame-ancestors 'none'"
X-Frame-Options = "DENY"
Or the Netlify _headers form:
/*
Content-Security-Policy: frame-ancestors 'none'
X-Frame-Options: DENY
On nginx:
add_header Content-Security-Policy "frame-ancestors 'none'" always;
add_header X-Frame-Options "DENY" always;
On Apache:
Header always set Content-Security-Policy "frame-ancestors 'none'"
Header always set X-Frame-Options "DENY"
frame-ancestors 'none': no site, not even your own, may frame these pages.'self': use this instead if your own app legitimately embeds its own pages.- A named partner: to allow exactly one trusted embedder, list its origin, for example
frame-ancestors https://app.example.com.
Already sending a
Content-Security-PolicyCSPHTTP headerContent-Security-Policy: a response header that whitelists exactly which scripts, styles, images and connections a page may use, so an injected payload simply has no permission to run.? Do not add a second one, browsers only honor the first CSP header. Appendframe-ancestors 'none'to your existing policy instead of sending a separate header.
Verify it
curl -sI https://yourdomain.com | grep -iE "frame-ancestors|x-frame-options"
A correct result shows content-security-policy: frame-ancestors 'none' (and, ideally, x-frame-options: DENY alongside it).
Proof
The hardened Content-Security-Policy on apecyber.com includes frame-ancestors 'none', so no other site can load it in a frame, and it scores A / 100 on Netlify. The ApeCyber scanner flags a missing frame-ancestorsframe-ancestorsCSP directiveThe CSP directive deciding who may embed your page in an <iframe>. Set to 'none' to make clickjacking impossible. passively on every scan, from the outside, touching nothing. Adding it is a clean −10 off the posture score.