diff --git src/wp-includes/media.php src/wp-includes/media.php
index bfd71cdcb3..96fdb5171b 100644
--- src/wp-includes/media.php
+++ src/wp-includes/media.php
@@ -1962,6 +1962,13 @@ function wp_img_tag_add_loading_attr( $image, $context ) {
  * @return string Converted `img` tag with `decoding` attribute added.
  */
 function wp_img_tag_add_decoding_attr( $image, $context ) {
+
+	// Only apply the decoding attribute to images that have a src attribute that
+	// starts with a double quote, ensuring escaped JSON is also excluded.
+	if ( false === strpos( $image, ' src="' ) ) {
+		return $image;
+	}
+
 	/**
 	 * Filters the `decoding` attribute value to add to an image. Default `async`.
 	 *
diff --git tests/phpunit/tests/media.php tests/phpunit/tests/media.php
index 0d5ac75863..a213308875 100644
--- tests/phpunit/tests/media.php
+++ tests/phpunit/tests/media.php
@@ -3162,6 +3162,31 @@ EOF;
 		$this->assertStringNotContainsString( ' loading=', $img );
 	}
 
+
+
+	/**
+	 * Test that decoding="async" is not applied to img tags with single quotes.
+	 *
+	 * @ticket 56969
+	 */
+	public function test_wp_img_tag_add_decoding_attr_with_single_quotes() {
+		$img = "<img src='example.png' alt=' width='300' height='225' />";
+		$img = wp_img_tag_add_decoding_attr( $img, 'test' );
+
+		$this->assertStringNotContainsString( ' decoding="async"', $img );
+	}
+
+	/**
+	 * Test that decoding="async" os not applied to img tags inside JSON.
+	 *
+	 * @ticket 56969
+	 */
+	public function test_decoding_async_not_applied_to_json() {
+		$content = '{"image": "<img src=\"example.png\" alt=\" width=\"300\" height=\"225\" />"}';
+		$content = wp_filter_content_tags( $content );
+		$this->assertStringNotContainsString( ' decoding="async"', $content );
+	}
+
 	/**
 	 * @ticket 50756
 	 */
