Content Security Policy
Last updated
Last updated
Content Security Policy is a mechanism to define which resources can be fetched out or executed by a web page. It lists and describes paths and sources, from which the browser can safely load resources. The resources may include images, frames, javascript and more.
Content Security Policy is implemented via a response header:
or the meta
element of the HTML page:
The browser follows the received policy and actively blocks violations as they are detected.
CSP works by restricting the origins that active and passive content can be loaded from. It can additionally restrict certain aspects of active content such as the execution of inline javascript, and the use of eval()
.
Resource loading policy is set using directives:
script-src specifies allowed sources for JavaScript. This includes not only URLs loaded directly into the <script>
elements but also things like inline script event handlers (such as onclick
) and XSLT stylesheets which can trigger script execution.
default-src defines the policy for fetching resources by default. When fetch directives are absent in the CSP header the browser follows this directive by default. The list of directives that do not follow default-src
:
base-uri
form-action
frame-ancestors
plugin-types
report-uri
sandbox
child-src defines valid sources for and nested browsing contexts loaded using elements such as <frame>
and <iframe>
.
connect-src restricts URLs to load using interfaces such as <a>
, fetch
, websocket
, XMLHttpRequest
.
frame-src specifies valid sources for nested browsing contexts loading using elements such as <frame>
and <iframe>
.
frame-ancestors specifies sources that can embed the current page. This directive applies to <frame>
, <iframe>
, <object>
, <embed>
, and <applet>
tags. This directive can't be used in <meta>
tags and applies only to non-HTML resources.
img-src defines allowed sources for loading images on the web page.
manifest-src defines allowed sources of application files.
media-src defines allowed sources from where media objects such as <audio>
, <video>
and <track>
can be loaded.
object-src defines allowed sources for the <object>
, <embed>
and <applet>
elements.
base-uri defines allowed URLs that can be loaded using <base>
element.
form-action lists valid endpoints for submission from <form>
tags. Whether form-action
should block redirects after a form submission is debated and browser implementations of this aspect are inconsistent (e.g. Firefox 57 does not block the redirects whereas Chrome 63 does).
plugin-types restricts the set of plugins that can be embedded into a document by limiting the types of resources which can be loaded. Instantiation of an <embed>
, <object>
or <applet>
elements will fail if:
the element to load does not declare a valid MIME-type
the declared type does not match one of the specified types in the plugin-types directive
the fetched resource does not match the declared type
upgrade-insecure-requests instructs browsers to rewrite URL schemes, changing HTTP to HTTPS. This directive can be useful for websites with large numbers of old URLs that need to be rewritten.
sandbox enables a sandbox for the requested resource similar to the <iframe>
sandbox attribute. It applies restrictions to a page's actions including preventing popups, preventing the execution of plugins and scripts, and enforcing a same-origin policy.
Sources are used to define the value of the directives:
* allows any URL except data:
, blob:
and filesystem:
.
<host-source> Internet host by name or IP address. The URL scheme, port number, and path are optional. Wildcards *
can be used for subdomains, host addresses, and port numbers, indicating that all legal values of each are valid.
<scheme-source> A scheme such as http:
or https:
(the colon is required). The data schemes can be specified as well:
data:
Allows data:
URLs to be used as a content source.
mediastream:
Allows mediastream:
URIs to be used as a content source.
blob:
Allows blob:
URIs to be used as a content source.
filesystem:
Allows filesystem:
URIs to be used as a content source.
self Refers to the origin from which the protected document is being served, including the same URL scheme and port number.
unsafe-eval Allows the use of eval()
and other unsafe methods for creating code from strings.
unsafe-hashes Allows enabling specific inline event handlers.
unsafe-inline Allows the use of inline resources, such as inline <script>
elements, javascript:
URLs, inline event handlers, and inline <style>
elements.
none Refers to the empty set; that is, no URLs match.
nonce-<base64-value> An allowlist for specific inline scripts using a cryptographic nonce (number used once). The server must generate a unique nonce value each time it transmits a policy.
<hash-algorithm>-<base64-value> A sha256
, sha384
or sha512
hash of scripts or styles. This value consists of the algorithm used to create the hash followed by a hyphen and the base64-encoded hash of the script or style.
Consider the following Content Security Policy:
The following image will be allowed as the image is loading from the same domain i.e. website.com
:
The following script will be allowed as the script is loading from the same domain i.e. website.com
:
The following script will not-allowed as the script is trying to load from an undefined domain i.e. attacker-website.com
:
The following payload will not-allowed on the page as inline scripts are blocked by default:
The following image will not-allowed as the image is loaded from an undefined domain i.e. attacker-website.com
:
Since the directive is not defined in the CSP img-src
is set to self
and follows default-src
by default.
You can use the following online tools to check Content Security Policy:
If script-src
or object-src
allows a public CDN by its domain name it is possible to access any data from that CDN, including vulnerable libraries or frameworks.
For example, in the snippet below the CSP allows https://cdnjs.cloudflare.com
and sets unsafe-eval
in script-src
. It allows using AngularJS
to execute arbitrary JavaScript code.
If script-src
or object-src
allows a domain where everyone can host arbitrary content it is possible to inject arbitrary content.
For example, in the snippet below the CSP allows https://storage.googleapis.com
in scripts-src
. It makes possible the uploading of a payload to GCP Cloud Storage and achieving arbitrary JavaScript execution.
If default-src
, script-src
, frame-src
or object-src
allows the data:
scheme it is possible to execute arbitrary JavaScript code by injecting a tag.
JSONP APIs work with the callback=
parameter, which specifies a function to process the data sent along with it. If there is no function name validation in JSONP, it is possible to inject a custom callback function and execute arbitrary JavaScript code.
JSONP APIs can be used to bypass a Content Security Policy. For example, the following CSP allows script loading from https://accounts.google.com
. Since https://accounts.google.com
hosts JSONP endpoints, they can be used to execute arbitrary code.
The exploitation does not require unsafe-inline
because the JSONP response handler script must be allowed in the CSP to serve legitimate requests.
References:
It is possible to bypass a CSP if it allows microsoft.com
in script-src
due to the CSP bypass found in WordPress.
References:
The snippet above uses the nonce
attribute value without even knowing it.
References:
If a Content Security Policy does not contain default-src
, frame-src
or object-src
, it is possible to combine other misconfigurations with tags injection to achieve arbitrary code execution.
For example, it is possible to use iframe
to bypass restrictions on script-src
, such as script-src 'none'
, script-src 'self'
, script-src 'nonce-*'
or script-src 'hash-*'
.
More examples that leverage other CSP misconfigurations to achieve arbitrary code execution:
If nonce
is static or is generated by a weak generator or its value can be guessed at, a policy can be bypassed by using the static nonce
or guessing the correct nonce
value.
References:
Content Security Policy allows you to specify paths in the required domain, like https://website.com/foo/bar/
or https://website.com/foo/bar/lib.js
. However, if a domain in the allowed list has an open redirect, that open redirect can be used to successfully load resources from allowed resources even if a path does not match the path allowed in the policy.
For example, the following policy allows two resources https://website.com
and https://partially-trusted-website.com/foo/bar.js
. If https://website.com
has an open redirect it is possible to load a script from another path at https://partially-trusted-website.com
.
Script restrictions in a Content Security Policy can be bypassed by interacting with scripts from allowed sources. Scripts may not work securely with data that can be controlled by a user, via DOM clobbering as an example. As a result, it may lead to arbitrary code execution.
For example, the following snippet calls a function in the global scope based on the arguments from markup:
As a result, this snippet can be used to invoke window.*
functions with arbitrary arguments using the following input
element:
Another example is the snippet below that passes a value of the RecaptchaClientUrl-
element to the src
attribute of the script
element:
So, the following payload can be used to execute arbitrary JavaScript code:
Check out the articles from the links below to learn more about finding gadgets.
References:
If there is a way to control files with arbitrary extensions to some path in the same domain it might be possible to abuse a CSP that sets script-src 'self'
and execute arbitrary JavaScript code.
If there is a way to control files with arbitrary extensions to some path in the same domain it might be possible to bypass nonce
and hash
based script-src
using the iframe
element (required misconfigured frame-src
).
Where /uploads/script.html
contains a payload:
Most likely an application will restrict uploading files with potentially dangerous extensions like html
or js
.
If X-Content-Type-Options: nosniff
is not active it is possible to use text files as sources for the script
element. In this case, browsers use MIME-type sniffing to find out the actual content type of a file.
For example, for the policy below, it is possible to use any text files with MIME-types text/plain
, text/css
, javasript/css
, etc. to load a script.
However, even if X-Content-Type-Options: nosniff
is active, there are content types that can be used to deliver a payload, check out:
If script-src
or default-src
allows unsafe-eval
, it might be possible to execute arbitrary JavaScript. There are multiple ways to achieve code execution:
There is an eval
expression that receives user-controlled data.
A website uses vulnerable frameworks, like jQuery or Angular.js, that can be used to execute any inline scripts.
If a Content Security Policy allows loading libraries and frameworks from public CDNs it is possible to use vulnerable libraries and frameworks to execute arbitrary code.
For example, the following CSP allows https://cdnjs.cloudflare.com
and sets unsafe-eval
in script-src
. The payload uses Angular JS
to execute arbitrary JavaScript code.
If default-src
, script-src
, frame-src
or object-src
allows unsafe-inline
it is possible to execute arbitrary JavaScript code by injecting a tag or using event handlers.
Content Security Policy can be generated dynamically based on variables provided by a user. If these variables are not properly validated, it may be possible to inject directives and weaken the policy.
References:
Using *
with script-src
, object-src
or default-src
allows content loading from an unlimited range of sources.
For example, the following CSP allows the direct loading of malicious scripts from arbitrary resources.
AngularJS can be used to bypass the CSP if it is used by the page or if the CSP allows loading from a remote resource.
The following example uses AngularJS events to access the window
object and escape from a sandbox.
In the next example, prototype.js
is used to access the window
object. In other words, the payload uses prototype.js
to access the window
object from AngularJS
.
More AngularJS payloads can be found at (part of the payloads require user interaction or unsafe-eval
to be set):
The following article explains the payload with prototype.js
and shows how to find similar libraries to escape a sandbox:
Vie.js can be used to bypass a CSP if unsafe-eval
is set (that is required for runtime template compilation).
More Vue.js payloads can be found at:
jQuery of different versions has vulnerabilities that can be used to bypass a CSP.
If there is a way to control an URL in $.get
or $.post
it is possible to bypass a CSP that sets nonce
and strict-dynamic
.
It was patched in jQuery 3.0.0, check out https://github.com/jquery/jquery/issues/2432
jQuery templates can be used to bypass a CSP that sets nonce
and unsafe-eval
(that is required for runtime template compilation).
Handlebar templates can be used to bypass a CSP that sets nonce
and unsafe-eval
(that is required for runtime template compilation).
Overwriting document.location
can be used to send data to an external server even if a CSP restricts the URLs which can be loaded.
See the full list of directives at .
See the full list of directive sources at .
contains ready-to-use JSONP endpoints on different websites.
If base-uri
is omitted or set to *
in a Content Security Policy, it is possible to redirect relative URLs to an attacker-controlled website by injecting the base
element, check out .