From e91083543a14bebcdaea99299ee446842532e916 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sun, 12 Jul 2026 15:19:56 +0100 Subject: [PATCH 1/2] Add tests demonstrating unsafe link filter over-blocking --- tests/unit/Util/RegexHelperTest.php | 32 +++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests/unit/Util/RegexHelperTest.php b/tests/unit/Util/RegexHelperTest.php index 143449aa2..7b91bba2f 100644 --- a/tests/unit/Util/RegexHelperTest.php +++ b/tests/unit/Util/RegexHelperTest.php @@ -402,6 +402,38 @@ public static function blockTypesWithInvalidCloserRegexes(): iterable yield [8]; } + /** + * @dataProvider dataForTestIsLinkPotentiallyUnsafe + */ + #[DataProvider('dataForTestIsLinkPotentiallyUnsafe')] + public function testIsLinkPotentiallyUnsafe(string $url, bool $expected): void + { + $this->assertSame($expected, RegexHelper::isLinkPotentiallyUnsafe($url)); + } + + /** + * @return iterable> + */ + public static function dataForTestIsLinkPotentiallyUnsafe(): iterable + { + return [ + // Dangerous leading schemes are unsafe + ['javascript:alert(1)', true], + ['JAVASCRIPT:alert(1)', true], + ['vbscript:msgbox(1)', true], + ['file:///etc/passwd', true], + ['data:text/html,', true], + ['data:image/svg+xml,', true], + // Safe data: images are allowed + ['data:image/png;base64,iVBORw0KGgo=', false], + // URLs merely containing those schemes elsewhere are safe + ['https://example.com/view?src=data:image/png', false], + ['https://example.com/download?to=file:report', false], + ['https://example.com/wiki/vbscript:_basics', false], + ['https://example.com/ok', false], + ]; + } + private function assertRegexMatches(string $pattern, string $string, string $message = ''): void { if (\method_exists($this, 'assertMatchesRegularExpression')) { From 433438115a514a557ef3a95859eea2238f2a6014 Mon Sep 17 00:00:00 2001 From: Graham Campbell Date: Sun, 12 Jul 2026 15:22:39 +0100 Subject: [PATCH 2/2] Anchor all REGEX_UNSAFE_PROTOCOL alternatives to the start of the URL --- src/Util/RegexHelper.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Util/RegexHelper.php b/src/Util/RegexHelper.php index 429b2d85f..3d9a2912e 100644 --- a/src/Util/RegexHelper.php +++ b/src/Util/RegexHelper.php @@ -66,7 +66,7 @@ final class RegexHelper '|' . '\((' . self::PARTIAL_ESCAPED_CHAR . '|[^()\x00])*+\))'; public const REGEX_PUNCTUATION = '/^[\p{P}\p{S}]/u'; - public const REGEX_UNSAFE_PROTOCOL = '/^javascript:|vbscript:|file:|data:/i'; + public const REGEX_UNSAFE_PROTOCOL = '/^(?:javascript|vbscript|file|data):/i'; public const REGEX_SAFE_DATA_PROTOCOL = '/^data:image\/(?:png|gif|jpeg|webp)/i'; public const REGEX_NON_SPACE = '/[^ \t\f\v\r\n]/';