The scientific fundament of Dr. Headerson

A Tale of Two Headers: A Formal Analysis of Inconsistent Click-Jacking Protection on the Web

Presented at the 29th USENIX Security Forum, August 12-14, 2020

Clickjacking protection on the internet is commonly enforced using browser security mechanisms. To control framing two solutions are available: the older X-Frame-Options header and the newer Content-Security-Policy header. Though these security mechanisms are certainly useful and successful, delegating protection to web browsers opens room for inconsistencies in the security guarantees offered to users of different browsers. In particular, inconsistencies might arise due to the lack of support for Content Security Policy and the different implementations of the X-Frame-Options header mechanisms.

We studied the problem of inconsistencies in framing control policies across different browsers. Moreover, we assessed the state of clickjacking protection on the Web. Our analysis of over 10,000 popular websites shows that 10% of the (distinct) framing control policies in the wild are inconsistent and most often do not provide any level of protection to at least one browser.

View in the CISPA Publication Database

In cooperation with:

Stefano Calzavara
Alvise Rabitti

Consistency of Content-Security-Policy and X-Frame-Options

For the consistency check we compare two different kinds of browsers: modern ones and legacy browsers. A browser is considered a modern browser if it does support the HTTP Headers Content-Security-Policy including the usage of the frame-ancestors directive of Content-Security-Policy. Modern browsers include Firefox, Safari, Edge, Chrome and many more. A browser is considered as legacy if it does not support Content-Security-Policy but does support X-Frame-Options HTTP headers. Legacy browser include Internet Explorer, Opera Mini and several years old versions of the now modern browsers.

Both, the older X-Frame-Options and the newer Content-Security-Policy header (precisely speaking its frame-ancestors directive) are used to instruct the browser if a certain webpage is allowed to be loaded within a frame or an iframe on another website. However, the newer Content-Security-Policy header is also more powerful and flexible and allows for a wider range of rules. For example, by using Content-Security-Policy it is possible to allow multiple different websites to embed your site within them. Contrary the X-Frame-Options header allows only to declare a single site, which is allowed to embed your website.


Seeing those two different kinds of browsers and two different kinds of headers we have a lot of different behaviors that need to be addressed. We consider the two HTTP headers X-Frame-Options and Content-Security-Policy consistent if they apply identical behavior for X-Frame-Options in legacy and Content-Security-Policy in modern browsers. Here are a few examples to help understand what happens.

Both headers, X-Frame-Options and Content-Security-Policy deny any embedding of the website. This is consistent for both X-Frame-Options and Content-Security-Policy across all browser, modern and legacy. Moreover, from a security point of view this is the most secure setting.

Both headers, X-Frame-Options and Content-Security-Policy only allow the website to embed itself. This is also consistent for both X-Frame-Options and Content-Security-Policy across all browsers, modern and legacy. This is the second best setting.

Both headers are not set at all and by this do not apply any rules at all. Not setting the headers will allow the website to be embedded in any website. This is considered a consistent ruleset as it enables the same behavior on modern and legacy browser. However, it is not recommended doing so as it does not prevent any attacks at all and leaves the site most vulnerable.


The headers are called "security-oriented" if they are not consistent and the Content-Security-Policy header allows more than the X-Frame-Options header. Moreover, the X-Frame-Options header does not allow anything that the Content-Security-Policy header does allow, thus the X-Frame-Options rules are a subset of the Content-Security-Policy rules. A security-oriented configuration can limit the functionality for legacy browsers, but is also more secure for users using such browsers.

The most simple case of a security-oriented configuration is a set X-Frame-Options header and a not set Content-Policy-Header. This allows all considering the Content-Security-Policy header, but restricts using X-Frame-Options. Thus X-Frame-Options restrictions are a subset of Content-Security-Policy restrictions and by this is considered security-oriented.

If both headers are set, but X-Frame-Options only allows SAMEORIGIN and Content-Security-Policy allows 'self' as well as we consider this a security-oriented configuration.


A "compatibility-oriented" configuration is similar to a security-oriented one. But with reversed roles, where the Content-Security-Policy restrictions are a subset of restrictions provided by the X-Frame-Options header. By this making sure, that users of legacy browsers have access to all functionality but possibly sacrificing some of their security.

An example of a compatibility-oriented configuration is one, where the X-Frame-Options is not set at all and allowing everything besides existing restrictions enforced by the Content-Security-Policy Header.


For a configuration to be considered inconsistent both headers have to be set. Moreover, both have to allow a website the other does not allow.

An example is X-Frame-Options only allowing and the Content-Security-Policy only allowing Both headers do something reasonable but totally different, resulting in an inconsistent configuration.