• tl;dr sec
  • Posts
  • Content Security Policy: Going From Idea to Afterthought

Content Security Policy: Going From Idea to Afterthought

GitHub security engineer Neil Matatall gives an overview of CSP: how it works, how to go from no CSP to a solid CSP, and how GitHub implements CSP.

Here’s a few quick notes from GitHub security engineer Neil Matatall’s talk at A Midsummer Night’s Con 2020, a virtual event hosted by Absolute AppSec.

In this talk, Neil gives an overview of Content Security Policy (CSP): how it works, how to go from no CSP to a solid CSP, and an explanation of strategies to create an effective and dynamic policy including code samples taken directly from the GitHub codebase.

Generate a Baseline CSP

Browser extensions like Caspr for Chrome and Laboratory by Firefox can help.


Making CSP violation reporting useful is actually hard in practice. A primary reason for this is many visitors to your site may have random extensions that inject content into pages that violate your CSP, their browser may be compromised, etc.

CSP reporting can be useful if you can restrict it a set of users who you know will have sane browser settings; for example, your employees.

Get Started, then Improve Over Time

You won’t be able to create a perfect policy from scratch at the beginning. They key is just to get started, even if your initial CSP is quite permissive. Then, ratchet up the restrictiveness over time.

This gives you some initial protection, and prevents the introduction of new code that makes your security posture worse.

Neil walks through a few examples of CSP policies and what cases they’d help prevent.

When you first get started, your CSP will probably look something like this. Not perfect, but good to get started.

Removing unsafe-inline and unsafe-eval can be quite difficult on large existing codebases, but are huge wins for security.

Allowing JavaScript only from your CDN is eventually where you want to be.


strict-dynamic can make CSP deployments easier, and can allow you to allow a enable specific scripts via a provided nonce or hash. Overview demo page.

From MDN: strict-dynamic “specifies that the trust explicitly given to a script present in the markup, by accompanying it with a nonce or a hash, shall be propagated to all the scripts loaded by that root script.”

How GitHub Implements CSP

Since CSP is just a response header, you can have different controllers, and even different endpoints on the same controller return different CSPs.

Each controller can set a class variable that customizes its CSP (CSP_EXCEPTIONS), or this can be done for one endpoint, for example, related to a specific feature.

CSP values can also be customized in ERB templates.

And set for static files as well: