missing-x-frame-options
Site can be embedded in other websites
Without an embedding policy, an attacker can load your site inside their own webpage and trick visitors into clicking buttons they didn't mean to click. The classic clickjacking setup.
What this means in plain English
Browsers can embed one website inside another using what’s called an iframe (think of the picture-in-picture box on a TV). Used properly, that’s how YouTube videos and Google Maps appear on external pages. Used maliciously, it lets an attacker load your site inside their own page, hide it under a transparent overlay, and trick visitors into clicking buttons on your site they never intended to.
Your site doesn’t currently send the instruction that prevents this. Whoever runs a website can load yours inside their own.
Why it matters to your business
This attack pattern is called clickjacking. The attacker:
- Hosts a webpage of their own with a tempting button — “Click to win”, “Continue”, whatever.
- Loads
your-site.example/account/delete(or/transfer-money,/grant-access) in a transparent iframe directly under the cursor. - The visitor clicks the bait button. The click actually lands on the hidden version of your site, which sees a perfectly legitimate request from a logged-in customer.
It works because cookies for your site are sent on every request made to it — including from inside the attacker’s iframe. The attacker never sees the cookie, doesn’t need to. They just need the click to land in the right place.
Variations on the same theme exist for mobile (tapjacking), social networks (likejacking), and form fields (typing into a fake input overlaid on a real one).
A frame-blocking instruction shuts the most efficient delivery method for this attack family.
How to fix it
Whoever runs your web server adds a one-line instruction. Two formats do the same job — modern browsers prefer the first, but the second still works everywhere and is easier to add as a single line:
Option A — modern, recommended:
Content-Security-Policy: frame-ancestors 'none'
That tells the browser: “no other website may load this site in an
iframe”. If your own site needs to embed itself (common for admin
dashboards), use 'self' instead. To allow specific partners:
'self' https://partner.example.
Option B — single-line, very wide compatibility:
X-Frame-Options: DENY
Or SAMEORIGIN if your site iframes itself.
Common server snippets:
nginx:
add_header Content-Security-Policy "frame-ancestors 'none'" always;
add_header X-Frame-Options DENY always;
Apache:
Header always set Content-Security-Policy "frame-ancestors 'none'"
Header always set X-Frame-Options DENY
After deployment, check with:
curl -I https://your-domain.example/ | grep -iE "frame-ancestors|x-frame-options"
A note on iframe-friendly products
If your product itself is an embeddable widget (chat, payments,
share buttons), set frame-ancestors to a specific list of customer
origins allowed to embed you. Don’t leave it open — adversarial
embedders can still trick users into clickjacking your widget for
actions like “approve payment” or “send message”.