Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2bf9709
attempt to bring 29807.8.diff up to date with trunk
adamsilverstein Feb 26, 2024
11336a3
Merge remote-tracking branch 'upstream/trunk' into pr/6184
azaozz Mar 11, 2024
05dcd69
Fix coding standards spaces and methods visibility
azaozz Mar 11, 2024
499dc82
More CS empty space fixes.
azaozz Mar 11, 2024
7a75eba
Merge branch 'trunk' into ticket/29807
adamsilverstein Aug 15, 2025
69312e7
Apply suggestion from @azaozz
adamsilverstein Aug 15, 2025
3c6defd
string in_array test
adamsilverstein Aug 15, 2025
c88673d
expand test slightly
adamsilverstein Aug 15, 2025
022def5
Cleanup; move multi_uri to parameter
adamsilverstein Aug 15, 2025
321e441
phpcbf
adamsilverstein Aug 15, 2025
c7c63dd
add sizes attribute to test
adamsilverstein Aug 15, 2025
e3c1684
enable sizes
adamsilverstein Aug 15, 2025
3862627
Improve doc block
adamsilverstein Aug 15, 2025
4cb049a
test clean up
adamsilverstein Aug 15, 2025
ca94908
Update tests/phpunit/tests/kses.php
adamsilverstein Aug 17, 2025
49f1ba6
Update src/wp-includes/kses.php
adamsilverstein Aug 17, 2025
2b5706c
remove unused $uris
adamsilverstein Aug 17, 2025
d116c8e
Add additional test cases.
adamsilverstein Aug 17, 2025
fbeed82
Merge branch 'trunk' into ticket/29807
adamsilverstein Aug 27, 2025
f9e002c
phpcbf
adamsilverstein Aug 27, 2025
80521e4
Merge remote-tracking branch 'origin/trunk' into ticket/29807
adamsilverstein Mar 13, 2026
0068aac
Add tests exposing srcset and img attribute bugs
adamsilverstein Mar 13, 2026
f11aeb2
Add decoding and fetchpriority to img allowed attrs
adamsilverstein Mar 13, 2026
cdb84fc
Fix srcset URI sanitization for URLs with commas
adamsilverstein Mar 13, 2026
399aa30
Fix array double arrow alignment in kses tests
adamsilverstein Mar 13, 2026
e5488a6
Merge branch 'trunk' into ticket/29807
adamsilverstein Mar 14, 2026
1f02276
Add kses srcset/picture tests, update @since tag
adamsilverstein Mar 14, 2026
9bb1ebf
Fix array double arrow alignment in new tests
adamsilverstein Mar 14, 2026
2bdc1f9
Merge branch 'trunk' into ticket/29807
adamsilverstein Mar 14, 2026
61881bf
Merge branch 'trunk' into ticket/29807
adamsilverstein Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 89 additions & 19 deletions src/wp-includes/kses.php
Original file line number Diff line number Diff line change
Expand Up @@ -210,17 +210,21 @@
),
'i' => array(),
'img' => array(
'alt' => true,
'align' => true,
'border' => true,
'height' => true,
'hspace' => true,
'loading' => true,
'longdesc' => true,
'vspace' => true,
'src' => true,
'usemap' => true,
'width' => true,
'alt' => true,
'align' => true,
'border' => true,
'decoding' => true,
'fetchpriority' => true,
'height' => true,
'hspace' => true,
'loading' => true,
'longdesc' => true,
'vspace' => true,
'src' => true,
'srcset' => true,
'usemap' => true,
'width' => true,
'sizes' => true,
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This attribute seems it should be moved up to appear before src to maintain alphabetic ordering.

),
'ins' => array(
'datetime' => true,
Expand Down Expand Up @@ -271,6 +275,7 @@
'p' => array(
'align' => true,
),
'picture' => array(),
'pre' => array(
'width' => true,
),
Expand All @@ -296,6 +301,12 @@
'align' => true,
),
'small' => array(),
'source' => array(
'srcset' => true,
'type' => true,
'media' => true,
'sizes' => true,
Comment on lines +305 to +308
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort?

),
'strike' => array(),
'strong' => array(),
'sub' => array(),
Expand Down Expand Up @@ -979,7 +990,6 @@ function wp_kses( $content, $allowed_html, $allowed_protocols = array() ) {
* @return string Filtered attribute.
*/
function wp_kses_one_attr( $attr, $element ) {
Comment thread
adamsilverstein marked this conversation as resolved.
$uris = wp_kses_uri_attributes();
$allowed_html = wp_kses_allowed_html( 'post' );
$allowed_protocols = wp_allowed_protocols();
$attr = wp_kses_no_null( $attr, array( 'slash_zero' => 'keep' ) );
Expand Down Expand Up @@ -1023,10 +1033,7 @@ function wp_kses_one_attr( $attr, $element ) {
// Sanitize quotes, angle braces, and entities.
$value = esc_attr( $value );

// Sanitize URI values.
if ( in_array( strtolower( $name ), $uris, true ) ) {
$value = wp_kses_bad_protocol( $value, $allowed_protocols );
}
$value = wp_kses_sanitize_uris( $name, $value, $allowed_protocols );

$attr = "$name=$quote$value$quote";
$vless = 'n';
Expand Down Expand Up @@ -1245,6 +1252,7 @@ function wp_kses_uri_attributes() {
'src',
'usemap',
'xmlns',
'srcset',
);

/**
Expand Down Expand Up @@ -1618,7 +1626,6 @@ function wp_kses_attr_check( &$name, &$value, &$whole, $vless, $element, $allowe
*/
function wp_kses_hair( $attr, $allowed_protocols ) {
$attributes = array();
$uris = wp_kses_uri_attributes();

$processor = new WP_HTML_Tag_Processor( "<wp {$attr}>" );
$processor->next_token();
Expand All @@ -1639,8 +1646,8 @@ function wp_kses_hair( $attr, $allowed_protocols ) {
foreach ( $attribute_names as $name ) {
$value = $processor->get_attribute( $name );
$is_bool = true === $value;
if ( is_string( $value ) && in_array( $name, $uris, true ) ) {
$value = wp_kses_bad_protocol( $value, $allowed_protocols );
if ( is_string( $value ) ) {
$value = wp_kses_sanitize_uris( $name, $value, $allowed_protocols );
}

// Reconstruct and normalize the attribute value.
Expand All @@ -1658,6 +1665,69 @@ function wp_kses_hair( $attr, $allowed_protocols ) {
return $attributes;
}

/**
* Sanitizes URI values in HTML attributes.
*
* This function centralizes logic for cleaning attribute values that are expected to contain URLs.
* It checks if the attribute name is one that should contain a URI (e.g., 'href', 'src', 'srcset').
* For attributes that can contain multiple URIs (such as 'srcset'), it splits the value and sanitizes each URI individually.
* All URI values are passed through {@see wp_kses_bad_protocol()} to remove disallowed protocols (e.g., 'javascript:').
*
* @since 7.1.0
*
* @param string $attrname The attribute name to test.
* @param string $attrvalue The attribute value to sanitize.
* @param string[] $allowed_protocols Array of allowed URL protocols.
* @param string[] $multi_uri Optional. Attributes that can contain multiple URIs. Default is array( 'srcset' ).
* @return string Sanitized attribute value.
*/
function wp_kses_sanitize_uris( $attrname, $attrvalue, $allowed_protocols, $multi_uri = array( 'srcset' ) ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think these can add PHP type hints as well for the params and the return value.

$uris = wp_kses_uri_attributes();

if ( ! in_array( strtolower( $attrname ), $uris, true ) ) {
return $attrvalue;
}

if ( in_array( strtolower( $attrname ), $multi_uri, true ) ) {
Comment on lines +1678 to +1691
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's add underscores to some vars, like $attr_name and $attr_value, and then let's add attrs to others, including $multi_uri_attrs and $uri_attrs. Otherwise, I was reading this and I was confused why attribute names would be among URIs.

/*
* Parse srcset-style attributes using the descriptor to find entry boundaries.
*
* Srcset entries are: URL [descriptor], URL [descriptor], ...
* Descriptors match patterns like "480w" or "2x".
*
* A naive split on commas breaks URLs that contain commas internally
* (e.g. CDN image resizer URLs like cdn-cgi/image/format=auto,quality=80/...).
*
* Instead, split on: whitespace + descriptor + comma (+ optional whitespace).
* This correctly identifies only the commas that separate srcset entries.
*/
$parts = preg_split( '/(\s+\d+[wx]\s*,\s*)/i', $attrvalue, -1, PREG_SPLIT_DELIM_CAPTURE );
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$parts = preg_split( '/(\s+\d+[wx]\s*,\s*)/i', $attrvalue, -1, PREG_SPLIT_DELIM_CAPTURE );
$parts = array_filter( (array) preg_split( '/(\s+\d+[wx]\s*,\s*)/i', $attrvalue, -1, PREG_SPLIT_DELIM_CAPTURE ) );

$result = '';

for ( $i = 0, $len = count( $parts ); $i < $len; $i++ ) {
if ( preg_match( '/^\s+\d+[wx]\s*,\s*$/i', $parts[ $i ] ) ) {
// This is a delimiter: space + descriptor + comma. Append it as-is.
$result .= $parts[ $i ];
} else {
// This is a URL (possibly with a trailing descriptor for the last entry).
$entry = $parts[ $i ];
Comment on lines +1707 to +1713
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using foreach can simplify this I believe.

Suggested change
for ( $i = 0, $len = count( $parts ); $i < $len; $i++ ) {
if ( preg_match( '/^\s+\d+[wx]\s*,\s*$/i', $parts[ $i ] ) ) {
// This is a delimiter: space + descriptor + comma. Append it as-is.
$result .= $parts[ $i ];
} else {
// This is a URL (possibly with a trailing descriptor for the last entry).
$entry = $parts[ $i ];
foreach( $parts as $entry ) {
if ( preg_match( '/^\s+\d+[wx]\s*,\s*$/i', $entry ) ) {
// This is a delimiter: space + descriptor + comma. Append it as-is.
$result .= $entry;
} else {
// This is a URL (possibly with a trailing descriptor for the last entry).
if ( preg_match( '/^(\s*)(.*?)(\s+\d+[wx])?\s*$/i', $entry, $m ) ) {

if ( preg_match( '/^(\s*)(.*?)(\s+\d+[wx])?\s*$/i', $entry, $m ) ) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use $matches instead of $m to avoid abbreviation.

$leading_ws = $m[1];
$url = $m[2];
$descriptor = isset( $m[3] ) ? $m[3] : '';
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
$descriptor = isset( $m[3] ) ? $m[3] : '';
$descriptor = $m[3] ?? '';

$result .= $leading_ws . wp_kses_bad_protocol( $url, $allowed_protocols ) . $descriptor;
} else {
$result .= wp_kses_bad_protocol( $entry, $allowed_protocols );
}
}
}

return $result;
}

return wp_kses_bad_protocol( $attrvalue, $allowed_protocols );
}

/**
* Finds all attributes of an HTML element.
*
Expand Down
Loading
Loading