Skip to content

Commit cdb84fc

Browse files
Fix srcset URI sanitization for URLs with commas
CDN image resizers (e.g. Cloudflare) use commas in URL paths like cdn-cgi/image/format=auto,quality=80,width=412/... which were incorrectly split by the naive comma-based preg_split in wp_kses_sanitize_uris(). This rewrites the splitting to use the srcset descriptor pattern (e.g. 480w, 2x) as entry boundaries, preserving commas within URLs. Also preserves original whitespace around separators instead of normalizing with implode.
1 parent f11aeb2 commit cdb84fc

2 files changed

Lines changed: 39 additions & 12 deletions

File tree

src/wp-includes/kses.php

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1686,19 +1686,46 @@ function wp_kses_sanitize_uris( $attrname, $attrvalue, $allowed_protocols, $mult
16861686

16871687
if ( ! in_array( strtolower( $attrname ), $uris, true ) ) {
16881688
return $attrvalue;
1689-
} else {
1690-
if ( in_array( strtolower( $attrname ), $multi_uri, true ) ) {
1691-
$thesevals = preg_split( '/\s*,\s*/', $attrvalue );
1692-
} else {
1693-
$thesevals = array( $attrvalue );
1694-
}
16951689
}
16961690

1697-
foreach ( (array) $thesevals as $key => $val ) {
1698-
$thesevals[ $key ] = wp_kses_bad_protocol( $val, $allowed_protocols );
1691+
if ( in_array( strtolower( $attrname ), $multi_uri, true ) ) {
1692+
/*
1693+
* Parse srcset-style attributes using the descriptor to find entry boundaries.
1694+
*
1695+
* Srcset entries are: URL [descriptor], URL [descriptor], ...
1696+
* Descriptors match patterns like "480w" or "2x".
1697+
*
1698+
* A naive split on commas breaks URLs that contain commas internally
1699+
* (e.g. CDN image resizer URLs like cdn-cgi/image/format=auto,quality=80/...).
1700+
*
1701+
* Instead, split on: whitespace + descriptor + comma (+ optional whitespace).
1702+
* This correctly identifies only the commas that separate srcset entries.
1703+
*/
1704+
$parts = preg_split( '/(\s+\d+[wx]\s*,\s*)/i', $attrvalue, -1, PREG_SPLIT_DELIM_CAPTURE );
1705+
$result = '';
1706+
1707+
for ( $i = 0, $len = count( $parts ); $i < $len; $i++ ) {
1708+
if ( preg_match( '/^\s+\d+[wx]\s*,\s*$/i', $parts[ $i ] ) ) {
1709+
// This is a delimiter: space + descriptor + comma. Append it as-is.
1710+
$result .= $parts[ $i ];
1711+
} else {
1712+
// This is a URL (possibly with a trailing descriptor for the last entry).
1713+
$entry = $parts[ $i ];
1714+
if ( preg_match( '/^(\s*)(.*?)(\s+\d+[wx])?\s*$/i', $entry, $m ) ) {
1715+
$leading_ws = $m[1];
1716+
$url = $m[2];
1717+
$descriptor = isset( $m[3] ) ? $m[3] : '';
1718+
$result .= $leading_ws . wp_kses_bad_protocol( $url, $allowed_protocols ) . $descriptor;
1719+
} else {
1720+
$result .= wp_kses_bad_protocol( $entry, $allowed_protocols );
1721+
}
1722+
}
1723+
}
1724+
1725+
return $result;
16991726
}
17001727

1701-
return implode( ', ', $thesevals );
1728+
return wp_kses_bad_protocol( $attrvalue, $allowed_protocols );
17021729
}
17031730

17041731
/**

tests/phpunit/tests/kses.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2502,7 +2502,7 @@ public function data_wp_kses_srcset() {
25022502
),
25032503
array(
25042504
'http://localhost/test.png,big 1x, bad://localhost/test.png,medium 2x',
2505-
'http://localhost/test.png, big 1x, //localhost/test.png, medium 2x',
2505+
'http://localhost/test.png,big 1x, //localhost/test.png,medium 2x',
25062506
),
25072507
array(
25082508
'path/to/test.png 1x, path/to/test-2x.png 2x',
@@ -2580,8 +2580,8 @@ public function data_wp_kses_srcset_edge_cases() {
25802580
// Test an empty srcset.
25812581
array( '', '' ),
25822582

2583-
// Srcset with extra whitespace.
2584-
array( ' image1.jpg 1x , image2.jpg 2x ', ' image1.jpg 1x, image2.jpg 2x ' ),
2583+
// Srcset with extra whitespace (trailing whitespace trimmed, internal spacing preserved).
2584+
array( ' image1.jpg 1x , image2.jpg 2x ', ' image1.jpg 1x , image2.jpg 2x' ),
25852585

25862586
// Srcset with single URL and no descriptor.
25872587
array( 'image.jpg', 'image.jpg' ),

0 commit comments

Comments
 (0)