Frozen by Nolimit SEO as 9012fe98, and it fixes something found here: the 1.1.0
glyph went through esc_attr() into a <style> element, where HTML entities are
not decoded by the CSS parser. It was protecting by coincidence rather than by
working, and Security found the case where the coincidence stops covering — a
backslash, which esc_attr leaves alone, is a CSS escape and swallows the
closing quote.
No injection was possible on any input any of us could construct, so this is
hardening rather than a hole, and the value comes from plugin code rather than
from a request.
The fix changes the alphabet instead of filtering the input: the glyph is
emitted as CSS numeric escapes, so what reaches the stylesheet is nothing but
backslashes, hex digits and spaces. cache-manager's statement of why that is
the right shape is the one worth keeping — the value CANNOT CONTAIN A
DELIMITER. "It escapes correctly" is a description, and a whitelist claims the
same description while needing to be kept honest against inputs nobody has
thought of yet.
Verified here rather than accepted:
- sha256 matches 9012fe98 before copying.
- The "b8d9284b plus two full stops and a phpcs pair" claim is comment-only,
measured with php -w over both: one sha256 for the stripped source.
- The escaper itself run against seven inputs including a bare backslash, a
quote, a CSS breakout, an HTML breakout and a NUL, asserting the output
matches nothing outside [backslash, hex, space]. All seven clean.
- Correct codepoints, and no mb_* calls, so the hand-written decoder holds on
installs without mbstring — which is every install none of us test on.
WPMGR_MENU_SHA updated in ci/plugin.conf. SEO's instruction said ci/static.sh,
which is their layout, not this one — following it literally would have set a
variable nothing reads, green on both sides while the check still asserted the
old value. Found by searching for the OLD VALUE rather than the path: zero
occurrences of any earlier frozen hash remain anywhere in ci/, tests/ or either
workflow root, and the new one appears exactly once.
Then proven consumed in both directions, which is the assertion that catches a
copy nothing reads: changing the file by one byte moves "got", and changing the
value in plugin.conf moves "expected".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>