From b6bb9d70867bda47d3afb39f337786e43ec78e66 Mon Sep 17 00:00:00 2001 From: HasnainAshfaq Date: Sat, 8 Aug 2026 04:32:34 +0500 Subject: [PATCH 1/2] Formatting: Allow CSS transform and SVG shape functions in safecss_filter_attr(). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #65457 added SVG presentation properties (transform, clip-path, fill, stroke, mask, marker-*) to the KSES CSS allowlist, but the two structures that govern their accepted value forms were not updated. This meant: - transform: rotate(45deg) — dropped (( character was rejected) - clip-path: url(#myClipper) — dropped (url() not validated for clip-path) - fill: url(#gradient1) — dropped (url() not validated for fill) Two changes: 1. Expand $css_url_data_types to include the SVG properties that accept url() references (clip-path, fill, stroke, mask, marker-*). This routes their values through the existing URL-validation path that already protects against javascript: and other bad protocols. 2. Extend the CSS function strip regex (the one that removes var(), calc(), etc. before the backslash/paren safety check) to also cover CSS transform functions (rotate, translate, scale, matrix, skew*, perspective) and CSS shape functions used in clip-path (inset, circle, ellipse, polygon, path). These are purely geometric/visual values with no script execution risk; the precedent is calc() (#46197), min/max (#55966), and CSS custom properties (#56353). Adds test cases for: - transform: rotate(), translate(), scale(), matrix(), skewX(), skewY() - Chained transform functions - clip-path: inset(), circle(), ellipse(), polygon() - clip-path: url(), fill: url(), mask: url(), marker-start/end: url() - Security regression: javascript: URLs in SVG url() references blocked Fixes #65832. Follow-up to #65457. --- src/wp-includes/kses.php | 12 +++++- tests/phpunit/tests/kses.php | 83 ++++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+), 1 deletion(-) diff --git a/src/wp-includes/kses.php b/src/wp-includes/kses.php index 92f866b15daef..6bdd8a7abfc2a 100644 --- a/src/wp-includes/kses.php +++ b/src/wp-includes/kses.php @@ -2906,6 +2906,16 @@ function safecss_filter_attr( $css, $deprecated = '' ) { 'list-style', 'list-style-image', + + // SVG presentation properties that accept url() references. + 'clip-path', + 'fill', + 'marker', + 'marker-end', + 'marker-mid', + 'marker-start', + 'mask', + 'stroke', ); /* @@ -3004,7 +3014,7 @@ function safecss_filter_attr( $css, $deprecated = '' ) { * Nested functions and parentheses are also removed, so long as the parentheses are balanced. */ $css_test_string = preg_replace( - '/\b(?:var|calc|min|max|minmax|clamp|repeat)(\((?:[^()]|(?1))*\))/', + '/\b(?:var|calc|min|max|minmax|clamp|repeat|rotate|rotateX|rotateY|rotateZ|rotate3d|translate|translateX|translateY|translateZ|translate3d|scale|scaleX|scaleY|scaleZ|scale3d|skew|skewX|skewY|matrix|matrix3d|perspective|inset|circle|ellipse|polygon|path)(\((?:[^()]|(?1))*\))/', '', $css_test_string ); diff --git a/tests/phpunit/tests/kses.php b/tests/phpunit/tests/kses.php index f560d88403524..2ac6b27ae4872 100644 --- a/tests/phpunit/tests/kses.php +++ b/tests/phpunit/tests/kses.php @@ -1224,6 +1224,7 @@ public function test_wp_kses_attr_no_attributes_allowed_with_false() { * @ticket 64414 * @ticket 65457 * @ticket 64974 + * @ticket 65832 * * @dataProvider data_safecss_filter_attr * @@ -1766,6 +1767,88 @@ public function data_safecss_filter_attr() { 'css' => 'text-anchor: middle', 'expected' => 'text-anchor: middle', ), + // SVG transform functions (ticket #65832). + array( + 'css' => 'transform: rotate(45deg)', + 'expected' => 'transform: rotate(45deg)', + ), + array( + 'css' => 'transform: translate(10px, 20px)', + 'expected' => 'transform: translate(10px, 20px)', + ), + array( + 'css' => 'transform: scale(1.5)', + 'expected' => 'transform: scale(1.5)', + ), + array( + 'css' => 'transform: matrix(1, 0, 0, 1, 10, 20)', + 'expected' => 'transform: matrix(1, 0, 0, 1, 10, 20)', + ), + array( + 'css' => 'transform: skewX(30deg)', + 'expected' => 'transform: skewX(30deg)', + ), + array( + 'css' => 'transform: skewY(30deg)', + 'expected' => 'transform: skewY(30deg)', + ), + // Multiple transform functions chained. + array( + 'css' => 'transform: rotate(45deg) scale(1.5)', + 'expected' => 'transform: rotate(45deg) scale(1.5)', + ), + // transform: none is unchanged (regression control). + array( + 'css' => 'transform: none', + 'expected' => 'transform: none', + ), + // SVG clip-path shape functions (ticket #65832). + array( + 'css' => 'clip-path: inset(10px)', + 'expected' => 'clip-path: inset(10px)', + ), + array( + 'css' => 'clip-path: circle(50%)', + 'expected' => 'clip-path: circle(50%)', + ), + array( + 'css' => 'clip-path: ellipse(25% 40% at 50% 50%)', + 'expected' => 'clip-path: ellipse(25% 40% at 50% 50%)', + ), + array( + 'css' => 'clip-path: polygon(50% 0%, 100% 100%, 0% 100%)', + 'expected' => 'clip-path: polygon(50% 0%, 100% 100%, 0% 100%)', + ), + // SVG url() references for allowlisted properties (ticket #65832). + array( + 'css' => 'clip-path: url(#myClipper)', + 'expected' => 'clip-path: url(#myClipper)', + ), + array( + 'css' => 'fill: url(#gradient1)', + 'expected' => 'fill: url(#gradient1)', + ), + array( + 'css' => 'mask: url(#myMask)', + 'expected' => 'mask: url(#myMask)', + ), + array( + 'css' => 'marker-start: url(#arrowStart)', + 'expected' => 'marker-start: url(#arrowStart)', + ), + array( + 'css' => 'marker-end: url(#arrowEnd)', + 'expected' => 'marker-end: url(#arrowEnd)', + ), + // Disallow javascript: URLs in SVG url() references (security regression). + array( + 'css' => 'fill: url(javascript:alert(1))', + 'expected' => '', + ), + array( + 'css' => 'clip-path: url(javascript:alert(1))', + 'expected' => '', + ), ); } From cf8c967ec6da85c4220d7b2709d53ecb48d1b765 Mon Sep 17 00:00:00 2001 From: Aki Hamano <54422211+t-hamano@users.noreply.github.com> Date: Sat, 8 Aug 2026 15:53:04 +0900 Subject: [PATCH 2/2] Add more test cases Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- tests/phpunit/tests/kses.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/phpunit/tests/kses.php b/tests/phpunit/tests/kses.php index 2ac6b27ae4872..02dc7768097f4 100644 --- a/tests/phpunit/tests/kses.php +++ b/tests/phpunit/tests/kses.php @@ -1840,6 +1840,18 @@ public function data_safecss_filter_attr() { 'css' => 'marker-end: url(#arrowEnd)', 'expected' => 'marker-end: url(#arrowEnd)', ), + array( + 'css' => 'marker-mid: url(#arrowMid)', + 'expected' => 'marker-mid: url(#arrowMid)', + ), + array( + 'css' => 'marker: url(#marker1)', + 'expected' => 'marker: url(#marker1)', + ), + array( + 'css' => 'stroke: url(#strokeGradient)', + 'expected' => 'stroke: url(#strokeGradient)', + ), // Disallow javascript: URLs in SVG url() references (security regression). array( 'css' => 'fill: url(javascript:alert(1))',