[wp-trac] [WordPress Trac] #63851: Audit wp_json_encode usage with script tags

WordPress Trac noreply at wordpress.org
Wed Aug 20 16:51:03 UTC 2025


#63851: Audit wp_json_encode usage with script tags
----------------------------+-------------------------
 Reporter:  jonsurrell      |       Owner:  (none)
     Type:  task (blessed)  |      Status:  new
 Priority:  normal          |   Milestone:  6.9
Component:  General         |     Version:
 Severity:  normal          |  Resolution:
 Keywords:  good-first-bug  |     Focuses:  javascript
----------------------------+-------------------------
Description changed by jonsurrell:

Old description:

> `wp_json_encode()` is used to print data in script tags in many places
> without the appropriate JSON flags.
>
> #62797 is an example of the general problem where `wp_json_encode( $data
> )` is insufficient to safely print data in a script tag.
>
> [https://sirre.al/2025/08/06/safe-json-in-script-tags-how-not-to-
> break-a-site/ A detailed analysis of the problem can be found here] where
> I recommend `wp_json_encode( $data, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES
> )` to encode data safely for use in script tags.
>
> Note that ''safe'' in this context means that the content will not alter
> the expected HTML document structure. The `SCRIPT` element will not close
> prematurely, nor will the element be prevented from closing at its
> apparent `</script>` close tag. ''Safe'' in this context has nothing to
> do with the behavior of the JavaScript when evaluated by the browser. The
> JavaScript behavior in unaffected by these changes.
>
> A good example of the ongoing issue is `wp_localize_script`. The
> following snippet breaks the containing script tag and prevents the
> script element from closing:
>
> {{{#!php
> <?php
> wp_enqueue_script( '_example', '/ex.js', array(), '0.0', false );
> wp_localize_script( '_example', '_', array( '<!--' => '<script>' ) );
> }}}
>
> This produces HTML like
>
> {{{
> <script id="_example-js-extra">
> var _ = {"<!--":"<script>"};
> </script>
> <script src="http://localhost:8888/ex.js?ver=0.0" id="_example-
> js"></script>
> …the rest of the HTML page
> }}}
>
> Resulting in a tree like
>
> {{{
> └─SCRIPT id="_example-js-extra"
>   └─#text  var _ = {"<!--":"<script>"}; </script> <script
> src="http://localhost:8888/ex.js?ver=0.0" id="_example-js"></script> …the
> rest of the HTML page
> }}}
>
> The SCRIPT element does not close as expected and the rest of the HTML
> page is part of the script contents.
>
> [60648] fixed the issue in #62797 and is a good example of the necessary
> changes.

New description:

 `wp_json_encode()` is used to print data in script tags in many places
 without the appropriate JSON flags.

 #62797 is an example of the general problem where `wp_json_encode( $data
 )` is insufficient to safely print data in a script tag.

 [https://sirre.al/2025/08/06/safe-json-in-script-tags-how-not-to-
 break-a-site/ A detailed analysis of the problem can be found here] where
 I recommend `wp_json_encode( $data, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES
 )` to encode data safely for use in script tags.

 Note that ''safe'' in this context means that the content will not alter
 the expected HTML document structure. The `SCRIPT` element will not close
 prematurely, nor will the element be prevented from closing at its
 apparent `</script>` close tag. ''Safe'' in this context has nothing to do
 with the behavior of the JavaScript when evaluated by the browser. The
 JavaScript behavior in unaffected by these changes.

 A good example of the ongoing issue is `wp_localize_script()`. The
 following snippet breaks the containing script tag and prevents the script
 element from closing:

 {{{#!php
 <?php
 wp_enqueue_script( '_example', '/ex.js', array(), '0.0', false );
 wp_localize_script( '_example', '_', array( '<!--' => '<script>' ) );
 }}}

 This produces HTML like

 {{{
 <script id="_example-js-extra">
 var _ = {"<!--":"<script>"};
 </script>
 <script src="http://localhost:8888/ex.js?ver=0.0" id="_example-
 js"></script>
 …the rest of the HTML page
 }}}

 Resulting in a tree like

 {{{
 └─SCRIPT id="_example-js-extra"
   └─#text  var _ = {"<!--":"<script>"}; </script> <script
 src="http://localhost:8888/ex.js?ver=0.0" id="_example-js"></script> …the
 rest of the HTML page
 }}}

 The SCRIPT element does not close as expected and the rest of the HTML
 page is part of the script contents.

 [60648] fixed the issue in #62797 and is a good example of the necessary
 changes.

--

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/63851#comment:4>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list