Opened 2 years ago
Last modified 4 weeks ago
#59446 new defect (bug)
Use script helper functions in admin to enable Content-Security-Policy opt-in
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | Future Release | Priority: | normal |
| Severity: | normal | Version: | 5.7 |
| Component: | Administration | Keywords: | has-patch |
| Focuses: | javascript | Cc: |
Description (last modified by )
In #58664 the script helper functions—wp_get_script_tag(), wp_print_inline_script_tag(), wp_get_inline_script_tag()—were leveraged to eliminate manual construction of script tags on the frontend and the login screen. These were introduced in #39941. This made it possible to opt-in (see example plugin) to a Strict Content-Security-Policy (Strict CSP) to guard against any possible XSS exploits. The scope in #58664 was limited to the frontend and the login screen because of the sheer number of inline scripts printed on the wp-admin. Additionally, the site editor and block editors make use of dynamically-constructed script tags in the editor iframe which is a Strict CSP violation.
Much of the work to rework inline scripts to use wp_print_inline_script() in the admin can be seen in an existing PR (now stale) from @enricocarraro.
See also #59444 which is about how to improve the developer experience of working with these JavaScript string literals.
Change History (17)
This ticket was mentioned in Slack in #core-performance by westonruter. View the logs.
2 years ago
#3
in reply to:
↑ 2
;
follow-up:
↓ 4
@
2 years ago
Replying to bedas:
Can I ask a clarification? I am confused on the "version" of this trac
It says 5.7 and the selector only allows up to 5.7.2
Good question. The version field here refers to when the first applicable version of WordPress that the issue is relevant to. Since the functions were introduced in 5.7, that's why this version is used.
The target version for fixing the issue is captured in the "milestone" field, which is still just Future Release. There isn't currently an established way to opt-in to CSP for the backend, so that's what this ticket is for.
#4
in reply to:
↑ 3
;
follow-up:
↓ 5
@
2 years ago
Replying to westonruter:
Thanks! Makes sense now.
I guess then there is some issue with wp_inline_script_attributes, because if it is intended for front end, then it shouldn't run in the backend - but does, and misses the array key type in that case.
I also notice that the documentation for the related wp_get_inline_script_tag is wrongly saying to use wp_script_attributes to filter the tags.
I guess I will open a commit/trac for the latter one and, should I open a trac for the first one? the very least we would need to specify on the doc page that this needs to be hooked explicitly to front end, or that an isset() should be run (which IMO is quite uncommon for filters/hooks, usually they run only where the data is available)
Finally, what about style tag? This is as far I see also not yet implemented (neither in the front nor in the backend)
Is there already a trac for that?
Please stop me if I am wrong. Thanks!
#5
in reply to:
↑ 4
@
2 years ago
Replying to bedas:
Replying to westonruter:
I guess then there is some issue withwp_inline_script_attributes, because if it is intended for front end, then it shouldn't run in the backend - but does, and misses the array keytypein that case. [...] the very least we would need to specify on the doc page that this needs to be hooked explicitly to front end, or that an isset() should be run (which IMO is quite uncommon for filters/hooks, usually they run only where the data is available)
This filter is not specific for the frontend. It is intended to be used in any context, whether frontend or admin. The type array key is only supplied automatically if the page is not HTML5. So yes, an isset() check should always be done for $attributes['type']. If it is not set, then it is assumed to be text/javascript, per the HTML spec.
I also notice that the documentation for the related
wp_get_inline_script_tagis wrongly saying to usewp_script_attributesto filter the tags.
Good catch. The phpdoc for wp_get_inline_script_tag() needs to be updated.
This ticket was mentioned in PR #9416 on WordPress/wordpress-develop by @debarghyabanerjee.
4 months ago
#7
- Keywords has-patch added; needs-patch removed
Trac Ticket: Core-63806
This pull request updates all inline script outputs in the bundled themes to use WordPress’s script helper functions, specifically wp_print_inline_script_tag(), in place of manually constructed <script> tags.
---
## ✅ Why This Matters
As of #59446, WordPress Core has adopted the use of wp_get_script_tag(), wp_get_inline_script_tag(), and wp_print_inline_script_tag() to eliminate manually constructed <script> tags. This change was made to:
However, many default and third-party themes still use raw <script> tags, which prevents them from fully benefiting from these improvements.
---
## 🛠 What’s Changed
- Replaced all instances of echo
'<script>...</script>'with calls towp_print_inline_script_tag().
---
## 🔙 Backward Compatibility
Since these helper functions were introduced in WordPress 5.7+, this PR also includes polyfill definitions in functions.php to ensure compatibility with earlier WordPress versions.
The polyfills conditionally define wp_print_inline_script_tag() and wp_get_inline_script_tag() functions only if they don’t already exist, making it safe for all supported versions.
@westonruter commented on PR #9416:
3 months ago
#9
@Debarghya-Banerjee Hello! Have you seen the latest PR feedback yet?
Also, note the comment I just added to the ticket, related the changes to Core-63887.
@debarghyabanerjee commented on PR #9416:
3 months ago
#10
Hi @westonruter , I have checked the comments and feedback, I am working on it, and will push the changes in sometime by today itself. Thanks.
@debarghyabanerjee commented on PR #9416:
3 months ago
#11
Hi @westonruter , Apologies for the late update. I’ve pushed the changes based on your and @sabernhardt 's feedback. Could you please take a look? Thanks!
@westonruter commented on PR #9416:
2 months ago
#12
@Debarghya-Banerjee Are you planning to address the remaining feedback or should we start pushing up commits to this PR? Thanks!
@debarghyabanerjee commented on PR #9416:
2 months ago
#13
Hi @westonruter , I have addressed the feedback. Sorry for getting back late. Can you please check once? Thanks.
@westonruter commented on PR #9416:
2 months ago
#14
I wrote a script that checked the output of rendered output of the homepages for each of the themes to verify that there were no regressions in the generated markup, and that only the expected changes occur:
<details><summary><code>grab-output.sh</code></summary>
#!/bin/bash
outdir=/tmp/trac-63806-output
mkdir -p "$outdir"
echo '' > "$outdir/report.md"
check_theme() {
theme="$1"
url="$2"
theme_dir="/tmp/trac-63806-output/$1"
echo "# $theme" >> "$outdir/report.md"
mkdir -p "$theme_dir"
npm run env:cli theme activate "$theme"
git checkout trunk
curl -s "$url" > "$theme_dir/before.html"
git checkout fix/63806-update-themes-to-use-wp_print_script_tag
curl -s "$url" > "$theme_dir/after.html"
prettier "$theme_dir/before.html" > "$theme_dir/before.prettier.html"
prettier "$theme_dir/after.html" > "$theme_dir/after.prettier.html"
diff -u "$theme_dir/before.html" "$theme_dir/after.html" > "$theme_dir/raw.diff"
diff -u "$theme_dir/before.prettier.html" "$theme_dir/after.prettier.html" > "$theme_dir/prettier.diff"
{
echo "URL: \`$url\`"
echo
echo 'Prettier Diff:'
echo '{{{diff'
cat "$theme_dir/prettier.diff"
echo '}}}'
echo
echo '<details><summary>Raw Diff</summary>'
echo
echo '{{{diff'
cat "$theme_dir/raw.diff"
echo '}}}'
echo
echo '</details>'
echo
} >> "$outdir/report.md"
}
home_url="http://localhost:8000/?enable_plugins=none"
check_theme twentyfifteen "$home_url"
check_theme twentyseventeen "$home_url"
check_theme twentysixteen "$home_url"
check_theme twentytwenty "$home_url"
check_theme twentytwentyone "$home_url"
cat "$outdir/report.md"
</details>
Here is the output:
# twentyfifteen
URL: http://localhost:8000/?enable_plugins=none
Prettier Diff:
-
/tmp/trac-63806-output/twentyfifteen/
old new 9 9 (function (html) { 10 10 html.className = html.className.replace(/\bno-js\b/, "js"); 11 11 })(document.documentElement); 12 //# sourceURL=twentyfifteen_javascript_detection 12 13 </script> 13 14 <title>WordPress Develop</title> 14 15 <meta name="robots" content="max-image-preview:large" />
<details><summary>Raw Diff</summary>
-
/tmp/trac-63806-output/twentyfifteen/
old new 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 6 <link rel="profile" href="https://gmpg.org/xfn/11"> 7 7 <link rel="pingback" href="http://localhost:8000/xmlrpc.php"> 8 <script>(function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement);</script> 8 <script> 9 (function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement); 10 //# sourceURL=twentyfifteen_javascript_detection 11 </script> 9 12 <title>WordPress Develop</title> 10 13 <meta name='robots' content='max-image-preview:large' /> 11 14 <link rel="alternate" type="application/rss+xml" title="WordPress Develop » Feed" href="http://localhost:8000/feed/" />
</details>
# twentyseventeen
URL: http://localhost:8000/?enable_plugins=none
Prettier Diff:
-
/tmp/trac-63806-output/twentyseventeen/
old new 9 9 (function (html) { 10 10 html.className = html.className.replace(/\bno-js\b/, "js"); 11 11 })(document.documentElement); 12 //# sourceURL=twentyseventeen_javascript_detection 12 13 </script> 13 14 <title>WordPress Develop</title> 14 15 <meta name="robots" content="max-image-preview:large" />
<details><summary>Raw Diff</summary>
-
/tmp/trac-63806-output/twentyseventeen/
old new 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 6 <link rel="profile" href="https://gmpg.org/xfn/11"> 7 7 8 <script>(function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement);</script> 8 <script> 9 (function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement); 10 //# sourceURL=twentyseventeen_javascript_detection 11 </script> 9 12 <title>WordPress Develop</title> 10 13 <meta name='robots' content='max-image-preview:large' /> 11 14 <link rel="alternate" type="application/rss+xml" title="WordPress Develop » Feed" href="http://localhost:8000/feed/" />
</details>
# twentysixteen
URL: http://localhost:8000/?enable_plugins=none
Prettier Diff:
-
/tmp/trac-63806-output/twentysixteen/
old new 8 8 (function (html) { 9 9 html.className = html.className.replace(/\bno-js\b/, "js"); 10 10 })(document.documentElement); 11 //# sourceURL=twentysixteen_javascript_detection 11 12 </script> 12 13 <title>WordPress Develop</title> 13 14 <meta name="robots" content="max-image-preview:large" />
<details><summary>Raw Diff</summary>
-
/tmp/trac-63806-output/twentysixteen/
old new 4 4 <meta charset="UTF-8"> 5 5 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 6 <link rel="profile" href="https://gmpg.org/xfn/11"> 7 <script>(function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement);</script> 7 <script> 8 (function(html){html.className = html.className.replace(/\bno-js\b/,'js')})(document.documentElement); 9 //# sourceURL=twentysixteen_javascript_detection 10 </script> 8 11 <title>WordPress Develop</title> 9 12 <meta name='robots' content='max-image-preview:large' /> 10 13 <link rel="alternate" type="application/rss+xml" title="WordPress Develop » Feed" href="http://localhost:8000/feed/" />
</details>
# twentytwenty
URL: http://localhost:8000/?enable_plugins=none
Prettier Diff:
-
/tmp/trac-63806-output/twentytwenty/
old new 618 618 <script> 619 619 document.documentElement.className = 620 620 document.documentElement.className.replace("no-js", "js"); 621 //# sourceURL=twentytwenty_no_js_class 621 622 </script> 622 623 <style id="custom-background-css"> 623 624 body.custom-background {
<details><summary>Raw Diff</summary>
-
/tmp/trac-63806-output/twentytwenty/
old new 78 78 <script src="http://localhost:8000/wp-content/themes/twentytwenty/assets/js/index.js?ver=2.9" id="twentytwenty-js-js" defer data-wp-strategy="defer"></script> 79 79 <link rel="https://api.w.org/" href="http://localhost:8000/wp-json/" /><link rel="EditURI" type="application/rsd+xml" title="RSD" href="http://localhost:8000/xmlrpc.php?rsd" /> 80 80 <meta name="generator" content="WordPress 6.9-alpha-60093-src" /> 81 <script>document.documentElement.className = document.documentElement.className.replace( 'no-js', 'js' );</script> 82 <style id="custom-background-css"> 81 <script> 82 document.documentElement.className = document.documentElement.className.replace( 'no-js', 'js' ); 83 //# sourceURL=twentytwenty_no_js_class 84 </script> 85 <style id="custom-background-css"> 83 86 body.custom-background { background-color: #fff; } 84 87 </style>
</details>
# twentytwentyone
URL: http://localhost:8000/?enable_plugins=none
Prettier Diff:
-
/tmp/trac-63806-output/twentytwentyone/
old new 1524 1524 </script> 1525 1525 <script> 1526 1526 document.body.classList.remove("no-js"); 1527 //# sourceURL=twenty_twenty_one_supports_js 1527 1528 </script> 1528 1529 <button 1529 1530 id="dark-mode-toggler" … … 1622 1623 1623 1624 darkModeInitialLoad(); 1624 1625 darkModeRepositionTogglerOnScroll(); 1626 //# sourceURL=http://localhost:8000/wp-content/themes/twentytwentyone/assets/js/dark-mode-toggler.js 1625 1627 </script> 1626 1628 <script> 1627 1629 if ( … … 1630 1632 ) { 1631 1633 document.body.classList.add("is-IE"); 1632 1634 } 1635 //# sourceURL=twentytwentyone_add_ie_class 1633 1636 </script> 1634 1637 <style id="core-block-supports-inline-css"> 1635 1638 /**
<details><summary>Raw Diff</summary>
-
/tmp/trac-63806-output/twentytwentyone/
old new 470 470 <script type="speculationrules"> 471 471 {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/twentytwentyone/*","/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} 472 472 </script> 473 <script>document.body.classList.remove("no-js");</script><button id="dark-mode-toggler" class="fixed-bottom" aria-pressed="false" onClick="toggleDarkMode()">Dark Mode: <span aria-hidden="true"></span></button> <style> 473 <script> 474 document.body.classList.remove('no-js'); 475 //# sourceURL=twenty_twenty_one_supports_js 476 </script> 477 <button id="dark-mode-toggler" class="fixed-bottom" aria-pressed="false" onClick="toggleDarkMode()">Dark Mode: <span aria-hidden="true"></span></button> <style> 474 478 #dark-mode-toggler > span { 475 479 margin-left: 5px; 476 480 } … … 482 486 } 483 487 </style> 484 488 485 <script>function toggleDarkMode() { // jshint ignore:line 489 <script> 490 function toggleDarkMode() { // jshint ignore:line 486 491 var toggler = document.getElementById( 'dark-mode-toggler' ); 487 492 488 493 if ( 'false' === toggler.getAttribute( 'aria-pressed' ) ) { … … 553 558 554 559 darkModeInitialLoad(); 555 560 darkModeRepositionTogglerOnScroll(); 556 </script> <script> 557 if ( -1 !== navigator.userAgent.indexOf( 'MSIE' ) || -1 !== navigator.appVersion.indexOf( 'Trident/' ) ) { 558 document.body.classList.add( 'is-IE' ); 559 } 560 </script> 561 <style id='core-block-supports-inline-css'> 561 //# sourceURL=http://localhost:8000/wp-content/themes/twentytwentyone/assets/js/dark-mode-toggler.js 562 </script> 563 <script> 564 if ( -1 !== navigator.userAgent.indexOf('MSIE') || -1 !== navigator.appVersion.indexOf('Trident/') ) { 565 document.body.classList.add('is-IE'); 566 } 567 //# sourceURL=twentytwentyone_add_ie_class 568 </script> 569 <style id='core-block-supports-inline-css'> 562 570 /** 563 571 * Core styles: block-supports 564 572 */
</details>
Can I ask a clarification? I am confused on the "version" of this trac
It says 5.7 and the selector only allows up to 5.7.2
Yet the trac was opened just 5 weeks ago, during a 6.x WP Version "timeframe". I am confused :)
What I am ultimately wondering is if there are ways already available for the _backend_ to become CSP ready, or if we only yet have https://core.trac.wordpress.org/ticket/39941 which implemented a front end filter allowing us to somewhat filter those script tags and add a nonce...
Thank you for any information!