Content Security Policy
Content Security Policy (CSP) overview
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.
How does it work?
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()
.
Directives
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 asonclick
) 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 web workers 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 manifest 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. Whetherform-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.
See the full list of directives at mdn web docs: Content-Security-Policy - Directives.
Source values
Sources are used to define the value of the directives:
* allows any URL except
data:
,blob:
andfilesystem:
.<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:
orhttps:
(the colon is required). The data schemes can be specified as well:data:
Allowsdata:
URLs to be used as a content source.mediastream:
Allowsmediastream:
URIs to be used as a content source.blob:
Allowsblob:
URIs to be used as a content source.filesystem:
Allowsfilesystem:
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
orsha512
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.
See the full list of directive sources at mdn web docs: Content-Security-Policy - CSP source values.
Example
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.
Bypassing techniques
You can use the following online tools to check Content Security Policy:
Allowed CDNs
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.
The presence of unsafe-eval
or unsafe-inline
sources significantly simplifies the exploitation of a vulnerable library or framework, since it allows directly calling the vulnerable component. Otherwise, it is necessary to find a way to call a vulnerable component.
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.
Allowed domains that host user contents
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.
data: scheme
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
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:
JSONBee contains ready-to-use JSONP endpoints on different websites.
Allowed microsoft.com in script-src by @OctagonNetworks
It is possible to bypass a CSP if it allows microsoft.com
in script-src
due to the CSP bypass found in WordPress.
References:
Missing or misconfigured base-uri
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 HTML Injection: base.
The snippet above uses the nonce
attribute value without even knowing it.
References:
Missing default-src, frame-src or object-src
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:
Nonce reuse
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:
Open redirects to bypass allowed paths
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 gadgets
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.
Script gadgets can be used to bypass CSP even if a nonce-based policy is in use because gadgets are usually allowed to execute JavaScript.
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:
Uploading custom files
Controlling executable files and script-src 'self'
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.
Controlling executable files and script-src 'nonce' or 'hash'
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:
Controlling text files and script-src 'self'
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:
unsafe-eval
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.
unsafe-inline
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.
Policy injection
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:
Wildcards *
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.
Frameworks and libraries
AngularJS
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:
Vue.js
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
jQuery of different versions has vulnerabilities that can be used to bypass a CSP.
nonce and strict-dynamic bypass via $.get in jQuery 2.x
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
nonce bypass via jQuery templates
jQuery templates can be used to bypass a CSP that sets nonce
and unsafe-eval
(that is required for runtime template compilation).
nonce bypass via hijacking handlebar templates
Handlebar templates can be used to bypass a CSP that sets nonce
and unsafe-eval
(that is required for runtime template compilation).
Data exfiltration
Overwriting document.location
Overwriting document.location
can be used to send data to an external server even if a CSP restricts the URLs which can be loaded.
Using the link HTML element
References
Last updated