Make WordPress Core

Opened 16 months ago

Last modified 2 weeks 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 16 months ago.

Download all attachments as: .zip

Change History (15)

#1 @swissspidy
16 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
16 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
16 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 16 months ago by johnbillion (previous) (diff)

#4 @tomdxw
16 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
14 months ago

  • Focuses javascript added

#6 @tomdxw
14 months ago

  • Keywords reporter-feedback removed

#7 @knutsp
11 months ago


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

#8 @maltris
9 months ago


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

#9 @herp
7 months ago


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

#10 @johnbillion
4 months ago

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

#11 @jrchamp
4 months 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

#12 @maestr055
3 months ago

+1 I'm busy with hardening my Wordpress sites. What is the status of this proposed change?

#13 @RagnarKarlsson
3 weeks ago

Has consideration been made to hook this, so that nonces can be included within security plugins (such as Ninjafirewall) which set a full CSP? Adding the header with just the script-src element as per the example plugin would be overwritten if a subsequent csp is defined in a second header.

#14 @giuse
2 weeks ago

How is it possible to include nonces for inline scripts? I haven't found any filter to do that. Is it possible with the current WordPress version? If not so, it would be great if WordPress gives the possibility to filter the output of <script type="text/javascript"> for inline scripts.

Note: See TracTickets for help on using tickets.