Skip to content

Commit bcf54f5

Browse files
authored
Merge commit from fork
Fix DisallowedRawHtml bypass via whitespace in HTML tag names
2 parents 0719b67 + 7a68ed1 commit bcf54f5

3 files changed

Lines changed: 25 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@ Updates should follow the [Keep a CHANGELOG](https://keepachangelog.com/) princi
66

77
## [Unreleased][unreleased]
88

9+
## [2.8.1] - 2026-03-05
10+
11+
This is a **security release** to address an issue where `DisallowedRawHtml` can be bypassed, resulting in a possible cross-site scripting (XSS) vulnerability.
12+
13+
### Fixed
14+
- Fixed `DisallowedRawHtmlRenderer` not blocking raw HTML tags with trailing ASCII whitespace (GHSA-4v6x-c7xx-hw9f)
15+
916
## [2.8.0] - 2025-11-26
1017

1118
### Added
@@ -717,7 +724,8 @@ No changes were introduced since the previous release.
717724
- Alternative 1: Use `CommonMarkConverter` or `GithubFlavoredMarkdownConverter` if you don't need to customize the environment
718725
- Alternative 2: Instantiate a new `Environment` and add the necessary extensions yourself
719726

720-
[unreleased]: https://github.com/thephpleague/commonmark/compare/2.8.0...HEAD
727+
[unreleased]: https://github.com/thephpleague/commonmark/compare/2.8.1...HEAD
728+
[2.8.1]: https://github.com/thephpleague/commonmark/compare/2.8.0...2.8.1
721729
[2.8.0]: https://github.com/thephpleague/commonmark/compare/2.7.1...2.8.0
722730
[2.7.1]: https://github.com/thephpleague/commonmark/compare/2.7.0...2.7.1
723731
[2.7.0]: https://github.com/thephpleague/commonmark/compare/2.6.2...2.7.0

src/Extension/DisallowedRawHtml/DisallowedRawHtmlRenderer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ public function render(Node $node, ChildNodeRendererInterface $childRenderer): ?
4545
return $rendered;
4646
}
4747

48-
$regex = \sprintf('/<(\/?(?:%s)[ \/>])/i', \implode('|', \array_map('preg_quote', $tags)));
48+
$regex = \sprintf('/<(\/?(?:%s)[\s\/>])/i', \implode('|', \array_map('preg_quote', $tags)));
4949

5050
// Match these types of tags: <title> </title> <title x="sdf"> <title/> <title />
5151
return \preg_replace($regex, '&lt;$1', $rendered);

tests/unit/Extension/DisallowedRawHtml/DisallowedRawHtmlRendererTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,16 @@ public static function dataProviderForTestWithDefaultSettings(): iterable
7171
yield ['<script>', '&lt;script>'];
7272
yield ['<plaintext>', '&lt;plaintext>'];
7373

74+
// Newline/whitespace bypass attempts (security fix)
75+
yield ['<script >', '&lt;script >'];
76+
yield ["<script\n>", "&lt;script\n>"];
77+
yield ["<script\t>", "&lt;script\t>"];
78+
yield ["<script\r\n>", "&lt;script\r\n>"];
79+
yield ["<iframe\nwidth=\"560\">", "&lt;iframe\nwidth=\"560\">"];
80+
81+
// Ensure non-disallowed tags with similar names are NOT filtered
82+
yield ['<scriptfoo>', '<scriptfoo>'];
83+
7484
// Tags not escaped by default
7585
yield ['<strong>', '<strong>'];
7686
}
@@ -107,6 +117,11 @@ public static function dataProviderForTestWithCustomSettings(): iterable
107117
yield ['<strong/>', '&lt;strong/>'];
108118
yield ['<strong />', '&lt;strong />'];
109119

120+
// Newline bypass with custom config
121+
yield ['<strong >', '&lt;strong >'];
122+
yield ["<strong\n>", "&lt;strong\n>"];
123+
yield ["<strong\t>", "&lt;strong\t>"];
124+
110125
// Defaults that I didn't include in my custom config
111126
yield ['<title>', '<title>'];
112127
yield ['<textarea>', '<textarea>'];

0 commit comments

Comments
 (0)