Opened 4 weeks ago
Last modified 4 weeks ago
#65871 new defect (bug)
KSES: the filter property is allowlisted but every filter function value is dropped by safecss_filter_attr()
| Reported by: | bejignesh | Owned by: | |
|---|---|---|---|
| Priority: | normal | Milestone: | Awaiting Review |
| Component: | Formatting | Version: | 5.9 |
| Severity: | normal | Keywords: | has-patch has-unit-tests |
| Cc: | Focuses: |
Description
Follow-up to #65832.
filter has been in the safecss_filter_attr() property allowlist since [52049] (#54336),
and [55564] (#57780) made url() values survive. The CSS filter functions were never added
to the function-stripping regular expression at wp-includes/kses.php:3018, so a declaration
using one still contains a ( when it reaches the check on line 3044 and is dropped in full.
Measured against trunk at [63180], PHP 8.3:
filter: blur(5px) => dropped filter: brightness(0.4) => dropped filter: contrast(200%) => dropped filter: drop-shadow(16px 16px 20px blue) => dropped filter: grayscale(50%) => dropped filter: hue-rotate(90deg) => kept filter: invert(75%) => dropped filter: opacity(25%) => dropped filter: saturate(30%) => dropped filter: sepia(60%) => dropped filter: blur(5px) brightness(0.4) => dropped filter: url(#svg-blur) => kept filter: none => kept
The one function that survives shows this is a gap rather than a policy. [63180] added the
transform functions, including rotate, and \brotate( matches inside hue-rotate(90deg)
because the hyphen is a word boundary. The function is stripped from the test string by
accident, leaving filter: hue- there, and the declaration passes. Nothing was decided
about hue-rotate specifically, and blur() is no more or less safe than it is.
This is the same "allowlisted in name only" state #65832 described for the SVG presentation
properties, with the same effect: for a user without unfiltered_html the property is
unusable in its canonical form.
Scope
backdrop-filter is not in the allowlist at all, so it is out of scope here.
The colour functions rgb(), rgba(), hsl(), color-mix() and friends are also dropped
everywhere, but that is #56391 and is not touched by this.
Patch adds the ten filter functions to the same alternation [63180] extended, and covers
each of them plus filter: none, filter: url(), a javascript: url and the unrelated
opacity property in the existing data provider.
Change History (1)
This ticket was mentioned in PR #13039 on WordPress/wordpress-develop by @bejignesh.
4 weeks ago
#1
- Keywords has-patch has-unit-tests added
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)
filterhas been in thesafecss_filter_attr()property allowlist since [52049], and[55564] made
url()values survive, but the CSS filter functions were never added to thefunction-stripping expression at
wp-includes/kses.php:3018. A declaration using one stillcontains a
(when it reaches the check below it, so it is dropped in full and the propertyis unusable in its canonical form for anyone without
unfiltered_html.Measured on trunk at [63180], PHP 8.3:
filter: blur(5px)filter: brightness(0.4)filter: contrast(200%)filter: drop-shadow(16px 16px 20px blue)filter: grayscale(50%)filter: hue-rotate(90deg)filter: invert(75%)filter: opacity(25%)filter: saturate(30%)filter: sepia(60%)filter: blur(5px) brightness(0.4)filter: url(#svg-blur)filter: nonehue-rotate()already passed, but not by design: [63180] addedrotatefor the transformfunctions and
\brotate(matches insidehue-rotate(90deg)because the hyphen is a wordboundary, leaving
filter: hue-in the test string. It is now matched by its own name.This is the same change [63180] made for the transform and basic shape functions. The value
is still re-emitted from the original declaration,
url()values still go throughwp_kses_bad_protocol(), and the test string check is unchanged, so the security model isthe same.
Not in scope:
backdrop-filteris not allowlisted at all, and the colour functionsrgb(),rgba(),hsl()andcolor-mix()are dropped everywhere, which is #56391.## Testing
12 of the new cases fail on trunk without the
kses.phpchange:1) Tests_Kses::test_safecss_filter_attr with data set #138 ('filter: blur(5px)', 'filter: blur(5px)') ... FAILURES! Tests: 163, Assertions: 163, Failures: 12.With the patch the full
ksesgroup is green, 487 tests / 1562 assertions, andphpcspasses on both changed files.
## Use of AI Tools
AI assistance: Yes
Tool(s): Claude Code
Model(s): Claude Opus 5
Used for: Drafting this description and a first pass at the test cases. I measured the
before and after behaviour myself, confirmed the tests fail without the patch, ran the
ksesgroup andphpcs, and I take responsibility for the change.