Skip to content

Commit 2997963

Browse files
pattonwebzclaude
andcommitted
docs/tests: address second-round review feedback on the sanitizer
- Correct the allow-list docblock: <a> is not excluded - wp_kses() has no namespace awareness, so the 'post' base list's entry also matches <a> inside <svg>. Safe: no on* attributes, protocol-validated href. - Reword the case-restoration map docblock - the allow-list stores lowercased names, not camelCase ones. - Make dangerous-construct test assertions case-insensitive so a lowercased <foreignobject> regression could not slip past them. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent ee91623 commit 2997963

2 files changed

Lines changed: 15 additions & 13 deletions

File tree

includes/helper-functions.php

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -793,12 +793,13 @@ function edac_parse_html_for_media( $html ) {
793793
* plus the minimal SVG vocabulary a flagged icon/logo/decorative graphic
794794
* actually uses: container, grouping, basic shapes, gradients, text, and the
795795
* accessible-name elements (<title>/<desc>). Deliberately excludes <script>,
796-
* <foreignObject>, <image>, <a> (SVG's own href-based link element -
797-
* ordinary post-content links are still allowed via the 'post' base list),
798-
* SMIL animation, filter primitives, and rarely-used structural extras
799-
* (<pattern>, <mask>, <marker>, <switch>, <textPath>) - none of which this
800-
* plugin's real-world content needs. Never lists any on* attribute for
801-
* anything.
796+
* <foreignObject>, <image>, SMIL animation, filter primitives, and
797+
* rarely-used structural extras (<pattern>, <mask>, <marker>, <switch>,
798+
* <textPath>) - none of which this plugin's real-world content needs. Note
799+
* that <a> IS allowed, via the 'post' base list: wp_kses() has no namespace
800+
* awareness, so that entry also matches <a> inside <svg> markup. That's safe
801+
* because no on* attribute is ever allowed on anything and href values get
802+
* core's bad-protocol validation.
802803
*
803804
* Every allowed SVG element shares one attribute set: wp_kses() only needs
804805
* attribute names allow-listed, not semantically scoped per tag, and a
@@ -865,8 +866,9 @@ function edac_scanned_html_allowed_tags(): array {
865866
* gradientTransform), but wp_kses() - built for case-insensitive HTML -
866867
* lowercases every attribute name it outputs. Left alone, that silently
867868
* breaks otherwise-safe SVGs (a lowercased viewbox is simply ignored by
868-
* browsers). Keyed by the lowercased name wp_kses() produces. Must stay in
869-
* sync with the camelCase attributes in edac_scanned_html_allowed_tags().
869+
* browsers). Keyed by the lowercased name wp_kses() produces. Every SVG
870+
* attribute with a case-sensitive canonical spelling that appears (lowercased)
871+
* in edac_scanned_html_allowed_tags() must have an entry here.
870872
*
871873
* @since x.x.x
872874
*

tests/phpunit/helper-functions/SanitizeScannedHtmlTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ class SanitizeScannedHtmlTest extends WP_UnitTestCase {
2121
public function test_strips_dangerous_constructs( $svg, $must_not_contain ) {
2222
$sanitized = edac_sanitize_scanned_html( $svg );
2323

24-
$this->assertStringNotContainsString( $must_not_contain, $sanitized );
24+
$this->assertStringNotContainsStringIgnoringCase( $must_not_contain, $sanitized );
2525
}
2626

2727
/**
@@ -48,10 +48,10 @@ public function test_combined_vector_payload_is_fully_stripped() {
4848
$svg = '<svg onload="alert(1)"><script>alert(2)</script><a onclick="alert(3)"><foreignObject><body>hi</body></foreignObject></a></svg>';
4949
$sanitized = edac_sanitize_scanned_html( $svg );
5050

51-
$this->assertStringNotContainsString( 'onload', $sanitized );
52-
$this->assertStringNotContainsString( '<script', $sanitized );
53-
$this->assertStringNotContainsString( 'onclick', $sanitized );
54-
$this->assertStringNotContainsString( 'foreignObject', $sanitized );
51+
$this->assertStringNotContainsStringIgnoringCase( 'onload', $sanitized );
52+
$this->assertStringNotContainsStringIgnoringCase( '<script', $sanitized );
53+
$this->assertStringNotContainsStringIgnoringCase( 'onclick', $sanitized );
54+
$this->assertStringNotContainsStringIgnoringCase( 'foreignObject', $sanitized );
5555
}
5656

5757
/**

0 commit comments

Comments
 (0)