Make WordPress Core

Opened 12 months ago

Last modified 11 days ago

#39941 accepted enhancement

Allow using Content-Security-Policy without unsafe-inline

Reported by: tomdxw Owned by: johnbillion
Milestone: 5.0 Priority: normal
Severity: normal Version: 4.8
Component: Security Keywords:
Focuses: javascript Cc:


Currently when using Content-Security-Policy with WordPress, you must use the unsafe-inline directive because there are a lot of blocks of inline JavaScript in WordPress core. This means that the browser cannot protect the user from attacks using XSS vulnerabilities. This is an unsatisfying situation because XSS vulnerabilities can be found in a great number of WordPress plugins.

The patch I’m providing today makes it possible to write a plugin which uses CSP without unsafe-inline. Such a plugin would make the vast majority of XSS vulnerabilities found in WP plugins useless to an attacker.

I’ve just added one new function: inline_js(). Now instead of writing <script>doSomething()</script>, you would write <?php inline_js(‘doSomething()’) ?>.

I’ve changed enough instances of inline JavaScript to use inline_js() that you can try it out:

I’ve only changed some instances of inline JavaScript in this patch - enough to prove that it will work.

Attachments (1)

inline-js-patch.diff (14.6 KB) - added by tomdxw 12 months ago.

Download all attachments as: .zip

Change History (12)

#1 @swissspidy
12 months ago

How does this change anything? inline_js() still prints <script></script> tags. Because of that, I think it's really a duplicate of #32067.

#2 @johnbillion
12 months ago

  • Keywords reporter-feedback added

Thanks for the patch, Tom.

The resulting output of inline_js() still includes inline <script> ... </script> tags. Can you let us know how this allows a CSP without unsafe-inline to be implemented?

#3 @johnbillion
12 months ago

Ah sorry, I didn't click through to your plugin. The nonce attribute approach is interesting. Is this widely supported by browsers? Can the same nonce be re-used for all script tags?

Last edited 12 months ago by johnbillion (previous) (diff)

#4 @tomdxw
12 months ago

Sorry, I should have explained better.

The CSP specification ( https://www.w3.org/TR/CSP2/ ) has two ways of allowing inline JavaScript: hashes and nonces.

I looked at hashes, but they would have required much larger changes to WordPress. And it would also require calculating multiple hashes on each page load which would have slowed the page down a small amount.

But with nonces you add a header like this:

Content-Security-Policy: script-src 'nonce-123abc'

And then whenever you use inline JavaScript, you add a nonce attribute to the script element:

<script nonce="123abc">

And when the browser encounters a script tag with the wrong nonce (or no nonce), it refuses to execute that JavaScript.

These nonces function in pretty much the same way as WordPress's nonces: so long as the attacker doesn't know what they are, they can't execute JavaScript. So when a plugin author writes <input value="<?php echo $_GET['x'] ?>">, an attacker isn't able to inject their own JavaScript because they don't know what the nonce is.

Is this widely supported by browsers?

Chrome and Firefox support it. Edge 38 (the current version) doesn't support CSP nonces. But Edge 39 does.

Here's the caniuse page: http://caniuse.com/#feat=contentsecuritypolicy2

Here's a very basic test page (if everything works you will see one alert box; if CSP isn't supported at all you will see two alert boxes; and if CSP is supported but nonces aren't, you won't see any alert boxes): https://cdn.rawgit.com/tomdxw/95a22a1be010b2d07152be6b3f635fa1/raw/039d6fe0876dfc0c689be0f5787c038d1f27f5d5/nonce-test.html

Can the same nonce be re-used for all script tags?

That's correct, yes. In the proof-of-concept plugin it uses the same nonce for every script tag.

#5 @tomdxw
9 months ago

  • Focuses javascript added

#6 @tomdxw
9 months ago

  • Keywords reporter-feedback removed

#7 @knutsp
7 months ago


Hard to secure a site using CSP with inline scripts and without a nonce on them.

#8 @maltris
5 months ago


The earlier this is included, the better. Just fell in that pit.

#9 @herp
3 months ago


Inpossible to get good security ratings with a CSP containing 'unsafe-inline'

#10 @johnbillion
11 days ago

  • Milestone changed from Awaiting Review to 5.0
  • Owner set to johnbillion
  • Status changed from new to accepted

#11 @jrchamp
11 days ago

@tomdxw I really like the idea here for inline. Can we extend it to external scripts too? 'strict-dynamic' seems to be the gold standard. https://www.w3.org/TR/CSP3/#strict-dynamic-usage

Note: See TracTickets for help on using tickets.