Headers

Fix Missing X-Frame-Options — Clickjacking Protection

Without X-Frame-Options, attackers can embed your page in an invisible iframe and trick users into clicking things they cannot see. One header line fixes it.

What clickjacking looks like

An attacker creates a page that embeds your site in a transparent iframe positioned exactly over a button on their page. The user thinks they are clicking the attacker's button but they are actually clicking on your site — transferring money, changing settings, or approving actions.

The fix by stack

Nginx

add_header X-Frame-Options "SAMEORIGIN" always;

Apache

Header always set X-Frame-Options "SAMEORIGIN"

Express

const helmet = require('helmet');
app.use(helmet.frameguard({ action: 'sameorigin' }));

Vercel (vercel.json)

{
  "headers": [{ "source": "/(.*)", "headers": [
    { "key": "X-Frame-Options", "value": "SAMEORIGIN" }
  ]}]
}

Cloudflare Transform Rules

Workers → Transform Rules → Response Headers → Add header: X-Frame-Options = SAMEORIGIN

SAMEORIGIN vs DENY

ValueAllowsUse when
SAMEORIGINYour own domain can embed the pageYou have admin panels or embedded pages on the same domain
DENYNo one can embed the pageLogin pages, checkout, any page where embedding should never happen

X-Frame-Options vs CSP frame-ancestors

CSP frame-ancestors is the modern replacement for X-Frame-Options. It is more flexible (supports multiple origins) and takes precedence when both are set. Use both for maximum browser compatibility:

# Nginx — both for full coverage
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Content-Security-Policy "frame-ancestors 'self';" always;

When both are present, browsers that support CSP use frame-ancestors and ignore X-Frame-Options. Older browsers fall back to X-Frame-Options.

Scan your security headers live → HeadersFixer