Analyzing a Content Security Policy circumvention for script injection and data exfiltration
Tags: webdev, security
Published: 2022-09-19 07:49:10

In today's news, a particular unsavoury website has had a script injection in place on its website, reportedly for quite some time:
{% embed https://twitter.com/GossiTheDog/status/1571566745638273027 %}

## What (might have) happened
The provided log entry shows that file with a `.opus` extension was requested from the server, with its referrer being the path `/test-chat`.  It's likely that it was added to the page as an `<iframe>` through some other content injection vector.  File extensions are often not particularly meaningful on the web, so the server and browser both can be just fine treating the `.opus` file as an HTML page to include as the contents of an inline frame.  

While the parent page reportedly had a Content Security Policy set via a meta tag that restricted scripts on the page, such a policy *does not* apply to the contents of nested iframes, which need their own policy.  As result the iframe is able to load a malicious script from an external domain without restriction.


## How bad was it?
Pretty bad. But also quite bad that it's just a link in a chain for the full exploit.
Preconditions for the full exploit are being able to (1) upload a file to the website's origin domain and (2) inject an iframe referring to that file elsewhere on the site.  
Normally iframe sandboxing restricts accessing the parent page's contents.  However, since the iframe's destination is hosted on the same domain as the parent page it has access to things such as cookies or `localStorage`, and can make further requests to the origin domain as the user and extract any data from the responses.  If a session key is accessible (by not being in a http-only cookie), it can be extracted and used to hijack the session, bypassing password and 2FA authentication.


## Prevention for savoury people
There's a bunch of measures that could make a vulnerability like this less likely to be exploited on your (savoury) site.

- The site admin provided an example of the page's Content Security Policy, which only included a `script-src` directive (though not entirely clear if their example was shortened to only what they thought was relevant).  If your site doesn't use iframes, then adding a `frame-src: 'none'` directive would prevent a similar content injection from being effective.  Even better would be to start with a restrictive `default-src`, and adding exceptions to more specific directives where necessary.  

- Having the web server add a restrictive policy to the headers served for any file resources - e.g. `default-src 'none'; frame-ancestors 'none'`, would prevent them from being embedded elsewhere, or being able to execute any scripts if accessed directly.  

- If any user-uploaded content is provided through a separate subdomain (e.g. `user-content.example.com`), then pages served from it don't have access to cookies restricted to the parent domain, and can't make requests impersonating the user to the main domain.  

- A Content Security Policy directive only including the top level domain (either explicitly or via `'self'`) would also not allow any subdomain content from being loaded where not wanted - e.g. `default-src 'self'; img-src 'self' user-content.example.com`.