diff --git a/src/wp-includes/media-template.php b/src/wp-includes/media-template.php index 20f485b5416e5..460cf3b3020e5 100644 --- a/src/wp-includes/media-template.php +++ b/src/wp-includes/media-template.php @@ -1619,11 +1619,17 @@ function wp_print_media_templates() { * The crossorigin attribute is added unconditionally to all relevant * media tags to ensure cross-origin isolation works regardless of * the final URL value at render time. + * + * IMG is intentionally excluded, matching wp_add_crossorigin_attributes(). + * Under Document-Isolation-Policy: isolate-and-credentialless the browser + * loads cross-origin images in credentialless mode without CORS headers, + * so adding crossorigin="anonymous" would force a CORS request and break + * previews of images served without Access-Control-Allow-Origin headers. */ $template_processor = new WP_HTML_Tag_Processor( $script_processor->get_modifiable_text() ); while ( $template_processor->next_tag() ) { if ( - in_array( $template_processor->get_tag(), array( 'AUDIO', 'IMG', 'VIDEO' ), true ) + in_array( $template_processor->get_tag(), array( 'AUDIO', 'VIDEO' ), true ) && ! is_string( $template_processor->get_attribute( 'crossorigin' ) ) ) { $template_processor->set_attribute( 'crossorigin', 'anonymous' ); diff --git a/tests/phpunit/tests/media/wpCrossOriginIsolation.php b/tests/phpunit/tests/media/wpCrossOriginIsolation.php index 1275ed21c3bc8..b1c40e8596780 100644 --- a/tests/phpunit/tests/media/wpCrossOriginIsolation.php +++ b/tests/phpunit/tests/media/wpCrossOriginIsolation.php @@ -538,4 +538,30 @@ public function test_output_buffer_handles_mixed_tags() { // Script and audio should have crossorigin. $this->assertSame( 2, substr_count( $output, 'crossorigin="anonymous"' ), 'Script and audio should both get crossorigin, but not img.' ); } + + /** + * IMG tags in the media manager templates must not receive + * crossorigin="anonymous", matching wp_add_crossorigin_attributes(). + * + * Adding the attribute forces a CORS request that breaks previews of + * images served without Access-Control-Allow-Origin headers, such as + * media offloaded to a CDN. + * + * @ticket 65673 + * + * @covers ::wp_print_media_templates + */ + public function test_print_media_templates_does_not_add_crossorigin_to_img() { + require_once ABSPATH . WPINC . '/media-template.php'; + + add_filter( 'wp_client_side_media_processing_enabled', '__return_true' ); + + ob_start(); + wp_print_media_templates(); + $output = ob_get_clean(); + + $this->assertMatchesRegularExpression( '/assertDoesNotMatchRegularExpression( '/]*\bcrossorigin\b/i', $output, 'IMG tags in the media templates must not receive a crossorigin attribute.' ); + $this->assertMatchesRegularExpression( '/<(?:audio|video)\b[^>]*crossorigin="anonymous"/i', $output, 'AUDIO and VIDEO tags in the media templates should still receive crossorigin="anonymous".' ); + } }