Skip to content

Security

Common Frame Protection mistakes that still ship

Framing controls only on the blog, missing frame-ancestors beside a decorative CSP, and "the WAF handles clickjacking" habits still ship—while public responses stay embeddable where it matters.

· by Jonas Reed

Common Frame Protection mistakes that still ship

I keep a lab notebook of framing mistakes that survive code review. None of them are exotic. They are ordinary shipping habits: controls on the wrong host, a CSP that never set frame-ancestors, or a team that pointed at a vendor dashboard instead of a response.

SlaySlop's Frame protection check "Looks for controls that prevent unwanted framing and clickjacking." The mistakes below are how teams still fail that public-surface test under green uptime.

Outcome if you fix these early

Fewer handoff calls where someone pastes a missing X-Frame-Options line into chat. Tickets that name URLs. A habit of reading framing-related directives instead of celebrating that "some security headers" exist.

Boundaries

Public read-only scanning. Permission required. Not a pentest. Frame protection ≠ CSP script policy. Content Security Policy "Checks whether browser content sources are restricted by a CSP header." Sibling, not synonym. SlaySlop will not rewrite your CDN config.

Loading diagram.

Mistake 1: Controls on the blog, not on login

Marketing pages get the security review because they were in the first design QA. /login and /checkout ride a different edge path and ship bare. Match paranoia on every host that takes credentials or money.

bash
curl -sI "https://www.example.com/blog/hello" | rg -i 'x-frame-options|content-security-policy'
curl -sI "https://www.example.com/login" | rg -i 'x-frame-options|content-security-policy'

Mistake 2: CSP present, framing still open

Teams ship a long Content-Security-Policy focused on script-src and never set frame-ancestors. The header key exists. The framing control may not. Read the policy text like a response shape, not like a badge.

Mistake 3: Meta tags instead of response headers

I still see pages that try to express framing policy only in HTML while CDNs strip or ignore the intent. Prefer response headers the browser and scanners actually observe on the public response.

Mistake 4: "The WAF handles it" without evidence

Maybe it does. Show the response. If the public curl does not show framing controls, the public surface does not show framing controls. Vendor consoles are not findings.

text
BUG: missing framing controls on /checkout
evidence: no X-Frame-Options; CSP lacks frame-ancestors
env: production

Mistake 5: Closing from a different host

Preview has DENY. Production apex redirects to www with a different edge config. Pin the host clients type. Rescan the same public URL SlaySlop cited.

Pitfalls that recreate the miss

Assuming SAMEORIGIN matches a multi-host product that embeds itself across sibling domains. Treating Report-Only CSP as enforcement. Declaring victory because Availability status is Up.

How I triage severity

Missing framing controls on login or checkout blocks my handoff. A low-traffic marketing page might wait, but I still file it with a URL. Impact ordering beats whichever Slack ping arrived last.

Mistake 6: Allowlist drift after a redesign

A partner embed was legitimate last year. The partnership ended. frame-ancestors still allows their origin. Or the reverse: a new partner needs embedding and someone "fixed" clickjacking by deleting controls entirely. Treat framing policy as product configuration with an owner, not a one-time harden ticket.

Mistake 7: Confusing cookie flags with framing controls

SameSite attributes matter for cookie behavior. They are not a substitute for X-Frame-Options or frame-ancestors. I still see tickets closed with cookie work while framing headers stay absent. Different mechanism. Different evidence.

When I reproduce, I keep the lab note to URL + raw header lines. That is enough to stop argument loops about whether "security middleware" was enabled.

Severity without drama

I block handoff for credential and payment paths with missing framing controls. I still file marketing gaps. I just order them. The lab notebook gets the URL first, then the raw header lines, then the proposed control. That order keeps reviews short.

Third-party hosted checkout pages are a special case: you may not control their headers. Document that boundary instead of pretending your apex DENY covers a processor domain you do not operate. Honesty here prevents false confidence in the portal.

I still prefer raw header evidence over screenshots of dashboards. Screenshots age badly. Header lines paste cleanly into tickets.

If a mistake keeps recurring across clients, add it to your agency template once instead of rediscovering it on every launch call.

Related next step

When I want a second pass, I run the launch URLs through SlaySlop and read Frame protection next to CSP before the demo. Soft link: Frame protection.