diff --git a/src/wp-admin/async-upload.php b/src/wp-admin/async-upload.php index 40b50e1e9907f..5fbdd370c5c1a 100644 --- a/src/wp-admin/async-upload.php +++ b/src/wp-admin/async-upload.php @@ -145,7 +145,7 @@ $_FILES['async-upload']['name'] ); - echo '\n"; + echo '\n"; exit; } diff --git a/src/wp-admin/customize.php b/src/wp-admin/customize.php index fbac0dd2420b5..07f74427d57f8 100644 --- a/src/wp-admin/customize.php +++ b/src/wp-admin/customize.php @@ -62,7 +62,7 @@ ?> diff --git a/src/wp-admin/edit-form-blocks.php b/src/wp-admin/edit-form-blocks.php index 837a6c6fe20f2..98f5c223f4017 100644 --- a/src/wp-admin/edit-form-blocks.php +++ b/src/wp-admin/edit-form-blocks.php @@ -115,7 +115,7 @@ static function ( $classes ) { wp_add_inline_script( 'wp-blocks', - sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( $post ) ) ), + sprintf( 'wp.blocks.setCategories( %s );', wp_json_encode( get_block_categories( $post ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' ); @@ -144,7 +144,7 @@ static function ( $classes ) { // Preload server-registered block schemas. wp_add_inline_script( 'wp-blocks', - 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings() ) . ');' + 'wp.blocks.unstable__bootstrapServerSideBlockDefinitions(' . wp_json_encode( get_block_editor_server_block_settings(), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ');' ); // Preload server-registered block bindings sources. @@ -158,7 +158,7 @@ static function ( $classes ) { 'usesContext' => $source->uses_context, ); } - $script = sprintf( 'for ( const source of %s ) { wp.blocks.registerBlockBindingsSource( source ); }', wp_json_encode( $filtered_sources ) ); + $script = sprintf( 'for ( const source of %s ) { wp.blocks.registerBlockBindingsSource( source ); }', wp_json_encode( $filtered_sources, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ); wp_add_inline_script( 'wp-blocks', $script @@ -178,7 +178,7 @@ static function ( $classes ) { ); wp_add_inline_script( 'wp-editor', - sprintf( 'var _wpMetaBoxUrl = %s;', wp_json_encode( $meta_box_url ) ), + sprintf( 'var _wpMetaBoxUrl = %s;', wp_json_encode( $meta_box_url, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'before' ); @@ -364,8 +364,8 @@ static function ( $classes ) { $init_script, $post->post_type, $post->ID, - wp_json_encode( $editor_settings ), - wp_json_encode( $initial_edits ) + wp_json_encode( $editor_settings, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $initial_edits, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ); wp_add_inline_script( 'wp-edit-post', $script ); diff --git a/src/wp-admin/includes/class-wp-internal-pointers.php b/src/wp-admin/includes/class-wp-internal-pointers.php index 6d7ebe958087a..09dc56ae3528e 100644 --- a/src/wp-admin/includes/class-wp-internal-pointers.php +++ b/src/wp-admin/includes/class-wp-internal-pointers.php @@ -120,7 +120,7 @@ private static function print_js( $pointer_id, $selector, $args ) { ?> \n", wp_json_encode( $args ) ); + printf( "\n", wp_json_encode( $args, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ); } } diff --git a/src/wp-admin/includes/class-wp-privacy-policy-content.php b/src/wp-admin/includes/class-wp-privacy-policy-content.php index 16fe3a689a0b9..c505df9b81644 100644 --- a/src/wp-admin/includes/class-wp-privacy-policy-content.php +++ b/src/wp-admin/includes/class-wp-privacy-policy-content.php @@ -348,7 +348,7 @@ public static function notice( $post = null ) { sprintf( 'wp.data.dispatch( "core/notices" ).createWarningNotice( "%s", { actions: [ %s ], isDismissible: false } )', $message, - wp_json_encode( $action ) + wp_json_encode( $action, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' ); diff --git a/src/wp-admin/includes/class-wp-themes-list-table.php b/src/wp-admin/includes/class-wp-themes-list-table.php index b17fb912d26dc..d7c491bd1c79e 100644 --- a/src/wp-admin/includes/class-wp-themes-list-table.php +++ b/src/wp-admin/includes/class-wp-themes-list-table.php @@ -357,7 +357,7 @@ public function _js_vars( $extra_args = array() ) { $args = array_merge( $args, $extra_args ); } - printf( "\n", wp_json_encode( $args ) ); + printf( "\n", wp_json_encode( $args, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ); parent::_js_vars(); } } diff --git a/src/wp-admin/includes/media.php b/src/wp-admin/includes/media.php index 22164aa65a72c..5fda1d9de2733 100644 --- a/src/wp-admin/includes/media.php +++ b/src/wp-admin/includes/media.php @@ -274,7 +274,7 @@ function media_send_to_editor( $html ) { ?> var resize_height = , resize_width = , - wpUploaderInit = ; + wpUploaderInit = ;
is_multisite() && ! is_upload_space_available(), ); - $script = 'var _wpPluploadSettings = ' . wp_json_encode( $settings ) . ';'; + $script = 'var _wpPluploadSettings = ' . wp_json_encode( $settings, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ';'; if ( $data ) { $script = "$data\n$script"; diff --git a/src/wp-includes/script-loader.php b/src/wp-includes/script-loader.php index 54193c841c7c3..def31178880d5 100644 --- a/src/wp-includes/script-loader.php +++ b/src/wp-includes/script-loader.php @@ -159,7 +159,8 @@ function wp_default_packages_vendor( $scripts ) { 'LLL' => __( 'F j, Y g:i a' ), 'LLLL' => null, ), - ) + ), + JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' @@ -384,7 +385,7 @@ function wp_default_packages_inline_scripts( $scripts ) { var preferencesStore = wp.preferences.store; wp.data.dispatch( preferencesStore ).setPersistenceLayer( persistenceLayer ); } ) ();', - wp_json_encode( $preload_data ), + wp_json_encode( $preload_data, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), $user_id ) ); @@ -477,7 +478,8 @@ function wp_default_packages_inline_scripts( $scripts ) { 'string' => $timezone_string, 'abbr' => $timezone_abbr, ), - ) + ), + JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' @@ -640,7 +642,7 @@ function wp_tinymce_inline_scripts() { $script = 'window.wpEditorL10n = { tinymce: { - baseURL: ' . wp_json_encode( includes_url( 'js/tinymce' ) ) . ', + baseURL: ' . wp_json_encode( includes_url( 'js/tinymce' ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) . ', suffix: ' . ( SCRIPT_DEBUG ? '""' : '".min"' ) . ', settings: ' . $init_obj . ', } @@ -1155,7 +1157,8 @@ function wp_default_scripts( $scripts ) { 'mejs.welsh' => __( 'Welsh' ), 'mejs.yiddish' => __( 'Yiddish' ), ), - ) + ), + JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'before' @@ -1999,7 +2002,8 @@ function wp_localize_jquery_ui_datepicker() { 'dateFormat' => $datepicker_date_format, 'firstDay' => absint( get_option( 'start_of_week' ) ), 'isRTL' => $wp_locale->is_rtl(), - ) + ), + JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); wp_add_inline_script( 'jquery-ui-datepicker', "jQuery(function(jQuery){jQuery.datepicker.setDefaults({$datepicker_defaults});});" ); @@ -2809,7 +2813,7 @@ function enqueue_editor_block_styles_assets() { $register_script_lines[] = sprintf( ' wp.blocks.registerBlockStyle( \'%s\', %s );', $block_name, - wp_json_encode( $block_style ) + wp_json_encode( $block_style, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ); } } diff --git a/src/wp-includes/speculative-loading.php b/src/wp-includes/speculative-loading.php index 2a06bc4aea03a..319e04d36ddde 100644 --- a/src/wp-includes/speculative-loading.php +++ b/src/wp-includes/speculative-loading.php @@ -247,7 +247,8 @@ function wp_print_speculation_rules(): void { wp_print_inline_script_tag( (string) wp_json_encode( - $speculation_rules + $speculation_rules, + JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), array( 'type' => 'speculationrules' ) ); diff --git a/src/wp-includes/theme-previews.php b/src/wp-includes/theme-previews.php index 7e0c085b1c102..8297dca0a2a70 100644 --- a/src/wp-includes/theme-previews.php +++ b/src/wp-includes/theme-previews.php @@ -49,7 +49,7 @@ function wp_attach_theme_preview_middleware() { 'wp-api-fetch', sprintf( 'wp.apiFetch.use( wp.apiFetch.createThemePreviewMiddleware( %s ) );', - wp_json_encode( sanitize_text_field( wp_unslash( $_GET['wp_theme_preview'] ) ) ) + wp_json_encode( sanitize_text_field( wp_unslash( $_GET['wp_theme_preview'] ) ), JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' ); @@ -70,7 +70,7 @@ function wp_block_theme_activate_nonce() { $nonce_handle = 'switch-theme_' . wp_get_theme_preview_path(); ?> get_data( 'customize-loader', 'data' ); diff --git a/src/wp-includes/widgets/class-wp-widget-custom-html.php b/src/wp-includes/widgets/class-wp-widget-custom-html.php index 0474e89bb2ec9..bdae2dd38eaa3 100644 --- a/src/wp-includes/widgets/class-wp-widget-custom-html.php +++ b/src/wp-includes/widgets/class-wp-widget-custom-html.php @@ -215,14 +215,14 @@ public function enqueue_admin_scripts() { ); wp_enqueue_script( 'custom-html-widgets' ); - wp_add_inline_script( 'custom-html-widgets', sprintf( 'wp.customHtmlWidgets.idBases.push( %s );', wp_json_encode( $this->id_base ) ) ); + wp_add_inline_script( 'custom-html-widgets', sprintf( 'wp.customHtmlWidgets.idBases.push( %s );', wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); if ( empty( $settings ) ) { $settings = array( 'disabled' => true, ); } - wp_add_inline_script( 'custom-html-widgets', sprintf( 'wp.customHtmlWidgets.init( %s );', wp_json_encode( $settings ) ), 'after' ); + wp_add_inline_script( 'custom-html-widgets', sprintf( 'wp.customHtmlWidgets.init( %s );', wp_json_encode( $settings, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' ); $l10n = array( 'errorNotice' => array( @@ -233,7 +233,7 @@ public function enqueue_admin_scripts() { // @todo This is lacking, as some languages have a dedicated dual form. For proper handling of plurals in JS, see #20491. ), ); - wp_add_inline_script( 'custom-html-widgets', sprintf( 'jQuery.extend( wp.customHtmlWidgets.l10n, %s );', wp_json_encode( $l10n ) ), 'after' ); + wp_add_inline_script( 'custom-html-widgets', sprintf( 'jQuery.extend( wp.customHtmlWidgets.l10n, %s );', wp_json_encode( $l10n, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ), 'after' ); } /** diff --git a/src/wp-includes/widgets/class-wp-widget-media-audio.php b/src/wp-includes/widgets/class-wp-widget-media-audio.php index d7bffd26481b6..7a8d5253a0b31 100644 --- a/src/wp-includes/widgets/class-wp-widget-media-audio.php +++ b/src/wp-includes/widgets/class-wp-widget-media-audio.php @@ -160,8 +160,8 @@ public function enqueue_admin_scripts() { $handle, sprintf( 'wp.mediaWidgets.modelConstructors[ %s ].prototype.schema = %s;', - wp_json_encode( $this->id_base ), - wp_json_encode( $exported_schema ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $exported_schema, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); @@ -172,9 +172,9 @@ public function enqueue_admin_scripts() { wp.mediaWidgets.controlConstructors[ %1$s ].prototype.mime_type = %2$s; wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n = _.extend( {}, wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n, %3$s ); ', - wp_json_encode( $this->id_base ), - wp_json_encode( $this->widget_options['mime_type'] ), - wp_json_encode( $this->l10n ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->widget_options['mime_type'], JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->l10n, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); } diff --git a/src/wp-includes/widgets/class-wp-widget-media-gallery.php b/src/wp-includes/widgets/class-wp-widget-media-gallery.php index a2527a6554231..9f76bc87106f1 100644 --- a/src/wp-includes/widgets/class-wp-widget-media-gallery.php +++ b/src/wp-includes/widgets/class-wp-widget-media-gallery.php @@ -148,8 +148,8 @@ public function enqueue_admin_scripts() { $handle, sprintf( 'wp.mediaWidgets.modelConstructors[ %s ].prototype.schema = %s;', - wp_json_encode( $this->id_base ), - wp_json_encode( $exported_schema ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $exported_schema, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); @@ -160,9 +160,9 @@ public function enqueue_admin_scripts() { wp.mediaWidgets.controlConstructors[ %1$s ].prototype.mime_type = %2$s; _.extend( wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n, %3$s ); ', - wp_json_encode( $this->id_base ), - wp_json_encode( $this->widget_options['mime_type'] ), - wp_json_encode( $this->l10n ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->widget_options['mime_type'], JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->l10n, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); } diff --git a/src/wp-includes/widgets/class-wp-widget-media-image.php b/src/wp-includes/widgets/class-wp-widget-media-image.php index b76536f7b2e1c..5977eb347c731 100644 --- a/src/wp-includes/widgets/class-wp-widget-media-image.php +++ b/src/wp-includes/widgets/class-wp-widget-media-image.php @@ -323,8 +323,8 @@ public function enqueue_admin_scripts() { $handle, sprintf( 'wp.mediaWidgets.modelConstructors[ %s ].prototype.schema = %s;', - wp_json_encode( $this->id_base ), - wp_json_encode( $exported_schema ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $exported_schema, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); @@ -335,9 +335,9 @@ public function enqueue_admin_scripts() { wp.mediaWidgets.controlConstructors[ %1$s ].prototype.mime_type = %2$s; wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n = _.extend( {}, wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n, %3$s ); ', - wp_json_encode( $this->id_base ), - wp_json_encode( $this->widget_options['mime_type'] ), - wp_json_encode( $this->l10n ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->widget_options['mime_type'], JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->l10n, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); } diff --git a/src/wp-includes/widgets/class-wp-widget-media-video.php b/src/wp-includes/widgets/class-wp-widget-media-video.php index fafb45f005df4..ad80f7d9d1c81 100644 --- a/src/wp-includes/widgets/class-wp-widget-media-video.php +++ b/src/wp-includes/widgets/class-wp-widget-media-video.php @@ -199,8 +199,8 @@ public function enqueue_admin_scripts() { $handle, sprintf( 'wp.mediaWidgets.modelConstructors[ %s ].prototype.schema = %s;', - wp_json_encode( $this->id_base ), - wp_json_encode( $exported_schema ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $exported_schema, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); @@ -211,9 +211,9 @@ public function enqueue_admin_scripts() { wp.mediaWidgets.controlConstructors[ %1$s ].prototype.mime_type = %2$s; wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n = _.extend( {}, wp.mediaWidgets.controlConstructors[ %1$s ].prototype.l10n, %3$s ); ', - wp_json_encode( $this->id_base ), - wp_json_encode( $this->widget_options['mime_type'] ), - wp_json_encode( $this->l10n ) + wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->widget_options['mime_type'], JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ), + wp_json_encode( $this->l10n, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); } diff --git a/src/wp-includes/widgets/class-wp-widget-text.php b/src/wp-includes/widgets/class-wp-widget-text.php index ba6c4fdfee0be..707c5f6e9c3e0 100644 --- a/src/wp-includes/widgets/class-wp-widget-text.php +++ b/src/wp-includes/widgets/class-wp-widget-text.php @@ -435,7 +435,7 @@ public function enqueue_admin_scripts() { wp_enqueue_editor(); wp_enqueue_media(); wp_enqueue_script( 'text-widgets' ); - wp_add_inline_script( 'text-widgets', sprintf( 'wp.textWidgets.idBases.push( %s );', wp_json_encode( $this->id_base ) ) ); + wp_add_inline_script( 'text-widgets', sprintf( 'wp.textWidgets.idBases.push( %s );', wp_json_encode( $this->id_base, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ) ) ); wp_add_inline_script( 'text-widgets', 'wp.textWidgets.init();', 'after' ); } diff --git a/tests/phpunit/tests/dependencies/wpLocalizeScript.php b/tests/phpunit/tests/dependencies/wpLocalizeScript.php index ed79d3e7bd5db..a57754973cf40 100644 --- a/tests/phpunit/tests/dependencies/wpLocalizeScript.php +++ b/tests/phpunit/tests/dependencies/wpLocalizeScript.php @@ -3,7 +3,7 @@ * @group dependencies * @group scripts */ -class Tests_Dependencies_LocalizeScript extends WP_UnitTestCase { +class Tests_Dependencies_wpLocalizeScript extends WP_UnitTestCase { /** * @var WP_Scripts */ @@ -38,4 +38,27 @@ public function test_wp_localize_script_works_before_enqueue_script() { ) ); } + + /** + * Verifies that wp_localize_script() outputs safe JSON whe harmful data is provided. + * + * @ticket 63851 + * @covers ::wp_localize_script + */ + public function test_wp_localize_script_outputs_safe_json() { + add_theme_support( 'html5', array( 'script' ) ); + + $path = '/test.js'; + $base_url = site_url( $path ); + + wp_enqueue_script( 'test-script', $path, array(), null ); + wp_localize_script( 'test-script', 'testData', array( '