Version in base suite: 2.3.9-1 Base version: php-league-commonmark_2.3.9-1 Target version: php-league-commonmark_2.3.9-1+deb12u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/p/php-league-commonmark/php-league-commonmark_2.3.9-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/p/php-league-commonmark/php-league-commonmark_2.3.9-1+deb12u1.dsc changelog | 9 control | 2 gbp.conf | 2 patches/0002-Fix-XSS-in-AttributesExtension.patch | 296 ++++++++++ patches/0003-Add-regression-test.patch | 42 + patches/0004-Fix-DisallowedRawHtml-bypass-via-newline-tab-in-tag-.patch | 47 + patches/0005-Fix-DomainFilteringAdapter-hostname-boundary-bypass.patch | 106 +++ patches/series | 4 8 files changed, 506 insertions(+), 2 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1yb6fqx1/php-league-commonmark_2.3.9-1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmp1yb6fqx1/php-league-commonmark_2.3.9-1+deb12u1.dsc: no acceptable signature found diff -Nru php-league-commonmark-2.3.9/debian/changelog php-league-commonmark-2.3.9/debian/changelog --- php-league-commonmark-2.3.9/debian/changelog 2023-02-15 17:38:28.000000000 +0000 +++ php-league-commonmark-2.3.9/debian/changelog 2026-03-26 07:15:50.000000000 +0000 @@ -1,3 +1,12 @@ +php-league-commonmark (2.3.9-1+deb12u1) bookworm; urgency=medium + + * Track Bookworm branch + * Fix XSS in AttributesExtension [CVE-2025-46734] + * Fix DisallowedRawHtml bypass via newline/tab in tag names [CVE-2026-30838] + * Fix DomainFilteringAdapter hostname boundary bypass [CVE-2026-33347] + + -- David Prévot Thu, 26 Mar 2026 08:15:50 +0100 + php-league-commonmark (2.3.9-1) unstable; urgency=medium [ Colin O'Dell ] diff -Nru php-league-commonmark-2.3.9/debian/control php-league-commonmark-2.3.9/debian/control --- php-league-commonmark-2.3.9/debian/control 2023-02-15 17:36:22.000000000 +0000 +++ php-league-commonmark-2.3.9/debian/control 2026-03-26 07:15:50.000000000 +0000 @@ -18,7 +18,7 @@ pkg-php-tools (>= 1.41~) Standards-Version: 4.6.2 Homepage: https://commonmark.thephpleague.com/ -Vcs-Git: https://salsa.debian.org/php-team/pear/php-league-commonmark.git -b debian/latest +Vcs-Git: https://salsa.debian.org/php-team/pear/php-league-commonmark.git -b debian/bookworm-security Vcs-Browser: https://salsa.debian.org/php-team/pear/php-league-commonmark Rules-Requires-Root: no diff -Nru php-league-commonmark-2.3.9/debian/gbp.conf php-league-commonmark-2.3.9/debian/gbp.conf --- php-league-commonmark-2.3.9/debian/gbp.conf 2022-01-25 18:18:49.000000000 +0000 +++ php-league-commonmark-2.3.9/debian/gbp.conf 2026-03-26 07:15:50.000000000 +0000 @@ -1,5 +1,5 @@ [DEFAULT] -debian-branch = debian/latest +debian-branch = debian/bookworm-security filter = [ '.gitattributes' ] pristine-tar = True upstream-vcs-tag = %(version%~%-)s diff -Nru php-league-commonmark-2.3.9/debian/patches/0002-Fix-XSS-in-AttributesExtension.patch php-league-commonmark-2.3.9/debian/patches/0002-Fix-XSS-in-AttributesExtension.patch --- php-league-commonmark-2.3.9/debian/patches/0002-Fix-XSS-in-AttributesExtension.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-league-commonmark-2.3.9/debian/patches/0002-Fix-XSS-in-AttributesExtension.patch 2026-03-26 07:15:50.000000000 +0000 @@ -0,0 +1,296 @@ +From: Colin O'Dell +Date: Mon, 5 May 2025 07:53:56 -0400 +Subject: Fix XSS in AttributesExtension + +Origin: backport, https://github.com/thephpleague/commonmark/commit/43207253ea5f14867c77c697cd3838c446cadcea +Bug: https://github.com/thephpleague/commonmark/security/advisories/GHSA-3527-qv2q-pfvx +Bug-Debian: https://security-tracker.debian.org/tracker/CVE-2025-46734 +--- + src/Extension/Attributes/AttributesExtension.php | 18 +++++- + .../Attributes/Event/AttributesListener.php | 15 ++++- + src/Extension/Attributes/Util/AttributesHelper.php | 38 +++++++++++++ + .../Extension/Attributes/data/allowlist.html | 3 + + .../Extension/Attributes/data/allowlist.md | 12 ++++ + .../Attributes/data/js_event_attributes.html | 1 + + .../Attributes/data/js_event_attributes.md | 1 + + .../Attributes/data/unsafe_links_allowed.html | 1 + + .../Attributes/data/unsafe_links_allowed.md | 5 ++ + .../Attributes/data/unsafe_links_blocked.html | 1 + + .../Attributes/data/unsafe_links_blocked.md | 5 ++ + .../Attributes/Util/AttributesHelperTest.php | 66 ++++++++++++++++++++++ + 12 files changed, 162 insertions(+), 4 deletions(-) + create mode 100644 tests/functional/Extension/Attributes/data/allowlist.html + create mode 100644 tests/functional/Extension/Attributes/data/allowlist.md + create mode 100644 tests/functional/Extension/Attributes/data/js_event_attributes.html + create mode 100644 tests/functional/Extension/Attributes/data/js_event_attributes.md + create mode 100644 tests/functional/Extension/Attributes/data/unsafe_links_allowed.html + create mode 100644 tests/functional/Extension/Attributes/data/unsafe_links_allowed.md + create mode 100644 tests/functional/Extension/Attributes/data/unsafe_links_blocked.html + create mode 100644 tests/functional/Extension/Attributes/data/unsafe_links_blocked.md + +diff --git a/src/Extension/Attributes/AttributesExtension.php b/src/Extension/Attributes/AttributesExtension.php +index 2ef3d85..b29606d 100644 +--- a/src/Extension/Attributes/AttributesExtension.php ++++ b/src/Extension/Attributes/AttributesExtension.php +@@ -19,14 +19,26 @@ use League\CommonMark\Event\DocumentParsedEvent; + use League\CommonMark\Extension\Attributes\Event\AttributesListener; + use League\CommonMark\Extension\Attributes\Parser\AttributesBlockStartParser; + use League\CommonMark\Extension\Attributes\Parser\AttributesInlineParser; +-use League\CommonMark\Extension\ExtensionInterface; ++use League\CommonMark\Extension\ConfigurableExtensionInterface; ++use League\Config\ConfigurationBuilderInterface; ++use Nette\Schema\Expect; + +-final class AttributesExtension implements ExtensionInterface ++final class AttributesExtension implements ConfigurableExtensionInterface + { ++ public function configureSchema(ConfigurationBuilderInterface $builder): void ++ { ++ $builder->addSchema('attributes', Expect::structure([ ++ 'allow' => Expect::arrayOf('string')->default([]), ++ ])); ++ } ++ + public function register(EnvironmentBuilderInterface $environment): void + { ++ $allowList = $environment->getConfiguration()->get('attributes.allow'); ++ $allowUnsafeLinks = $environment->getConfiguration()->get('allow_unsafe_links'); ++ + $environment->addBlockStartParser(new AttributesBlockStartParser()); + $environment->addInlineParser(new AttributesInlineParser()); +- $environment->addEventListener(DocumentParsedEvent::class, [new AttributesListener(), 'processDocument']); ++ $environment->addEventListener(DocumentParsedEvent::class, [new AttributesListener($allowList, $allowUnsafeLinks), 'processDocument']); + } + } +diff --git a/src/Extension/Attributes/Event/AttributesListener.php b/src/Extension/Attributes/Event/AttributesListener.php +index feec8cc..fa068f4 100644 +--- a/src/Extension/Attributes/Event/AttributesListener.php ++++ b/src/Extension/Attributes/Event/AttributesListener.php +@@ -29,6 +29,19 @@ final class AttributesListener + private const DIRECTION_PREFIX = 'prefix'; + private const DIRECTION_SUFFIX = 'suffix'; + ++ /** @var list */ ++ private array $allowList; ++ private bool $allowUnsafeLinks; ++ ++ /** ++ * @param list $allowList ++ */ ++ public function __construct(array $allowList = [], bool $allowUnsafeLinks = true) ++ { ++ $this->allowList = $allowList; ++ $this->allowUnsafeLinks = $allowUnsafeLinks; ++ } ++ + public function processDocument(DocumentParsedEvent $event): void + { + foreach ($event->getDocument()->iterator() as $node) { +@@ -50,7 +63,7 @@ final class AttributesListener + $attributes = AttributesHelper::mergeAttributes($node->getAttributes(), $target); + } + +- $target->data->set('attributes', $attributes); ++ $target->data->set('attributes', AttributesHelper::filterAttributes($attributes, $this->allowList, $this->allowUnsafeLinks)); + } + + $node->detach(); +diff --git a/src/Extension/Attributes/Util/AttributesHelper.php b/src/Extension/Attributes/Util/AttributesHelper.php +index de5c111..33d3a0a 100644 +--- a/src/Extension/Attributes/Util/AttributesHelper.php ++++ b/src/Extension/Attributes/Util/AttributesHelper.php +@@ -134,4 +134,42 @@ final class AttributesHelper + + return $attributes; + } ++ ++ /** ++ * @param array $attributes ++ * @param list $allowList ++ * ++ * @return array ++ */ ++ public static function filterAttributes(array $attributes, array $allowList, bool $allowUnsafeLinks): array ++ { ++ $allowList = \array_fill_keys($allowList, true); ++ ++ foreach ($attributes as $name => $value) { ++ $attrNameLower = \strtolower($name); ++ ++ // Remove any unsafe links ++ if (! $allowUnsafeLinks && ($attrNameLower === 'href' || $attrNameLower === 'src') && \is_string($value) && RegexHelper::isLinkPotentiallyUnsafe($value)) { ++ unset($attributes[$name]); ++ continue; ++ } ++ ++ // No allowlist? ++ if ($allowList === []) { ++ // Just remove JS event handlers ++ if (\str_starts_with($attrNameLower, 'on')) { ++ unset($attributes[$name]); ++ } ++ ++ continue; ++ } ++ ++ // Remove any attributes not in that allowlist (case-sensitive) ++ if (! isset($allowList[$name])) { ++ unset($attributes[$name]); ++ } ++ } ++ ++ return $attributes; ++ } + } +diff --git a/tests/functional/Extension/Attributes/data/allowlist.html b/tests/functional/Extension/Attributes/data/allowlist.html +new file mode 100644 +index 0000000..92ab9de +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/allowlist.html +@@ -0,0 +1,3 @@ ++

Header with attributes

++

some text

++

image

+diff --git a/tests/functional/Extension/Attributes/data/allowlist.md b/tests/functional/Extension/Attributes/data/allowlist.md +new file mode 100644 +index 0000000..996c647 +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/allowlist.md +@@ -0,0 +1,12 @@ ++--- ++attributes: ++ allow: [id, class, align] ++--- ++ ++Header with attributes {#header1} ++--------------------------------- ++ ++{class="text" hello="world"} ++some text ++ ++![image](/assets/image.jpg){align=left width=100px} +diff --git a/tests/functional/Extension/Attributes/data/js_event_attributes.html b/tests/functional/Extension/Attributes/data/js_event_attributes.html +new file mode 100644 +index 0000000..667c05e +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/js_event_attributes.html +@@ -0,0 +1 @@ ++

this extension blocks js event attributes

+diff --git a/tests/functional/Extension/Attributes/data/js_event_attributes.md b/tests/functional/Extension/Attributes/data/js_event_attributes.md +new file mode 100644 +index 0000000..e0a0642 +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/js_event_attributes.md +@@ -0,0 +1 @@ ++![this extension blocks js event attributes](){onerror=alert(1) class=blocked} +diff --git a/tests/functional/Extension/Attributes/data/unsafe_links_allowed.html b/tests/functional/Extension/Attributes/data/unsafe_links_allowed.html +new file mode 100644 +index 0000000..3497e89 +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/unsafe_links_allowed.html +@@ -0,0 +1 @@ ++

click me

+diff --git a/tests/functional/Extension/Attributes/data/unsafe_links_allowed.md b/tests/functional/Extension/Attributes/data/unsafe_links_allowed.md +new file mode 100644 +index 0000000..9a1d45e +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/unsafe_links_allowed.md +@@ -0,0 +1,5 @@ ++--- ++allow_unsafe_links: true ++--- ++ ++[click me](javascript:alert(1)){href="javascript:alert(1)"} +diff --git a/tests/functional/Extension/Attributes/data/unsafe_links_blocked.html b/tests/functional/Extension/Attributes/data/unsafe_links_blocked.html +new file mode 100644 +index 0000000..0205a6b +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/unsafe_links_blocked.html +@@ -0,0 +1 @@ ++

click me

+diff --git a/tests/functional/Extension/Attributes/data/unsafe_links_blocked.md b/tests/functional/Extension/Attributes/data/unsafe_links_blocked.md +new file mode 100644 +index 0000000..5c706a3 +--- /dev/null ++++ b/tests/functional/Extension/Attributes/data/unsafe_links_blocked.md +@@ -0,0 +1,5 @@ ++--- ++allow_unsafe_links: false ++--- ++ ++[click me](javascript:alert(1)){href="javascript:alert(1)"} +diff --git a/tests/unit/Extension/Attributes/Util/AttributesHelperTest.php b/tests/unit/Extension/Attributes/Util/AttributesHelperTest.php +index 17a4653..67767c5 100644 +--- a/tests/unit/Extension/Attributes/Util/AttributesHelperTest.php ++++ b/tests/unit/Extension/Attributes/Util/AttributesHelperTest.php +@@ -182,4 +182,70 @@ final class AttributesHelperTest extends TestCase + ['id' => 'block', 'class' => 'inline block'], + ]; + } ++ ++ /** ++ * @dataProvider dataForTestFilterAttributes ++ * ++ * @param array $attributes ++ * @param list $allowList ++ * @param array $expected ++ */ ++ public function testFilterAttributes(array $attributes, array $allowList, bool $allowUnsafeLinks, array $expected): void ++ { ++ $this->assertEquals($expected, AttributesHelper::filterAttributes($attributes, $allowList, $allowUnsafeLinks)); ++ } ++ ++ /** ++ * @return iterable> ++ */ ++ public static function dataForTestFilterAttributes(): iterable ++ { ++ // No allow list; unsafe links disallowed (default behavior) ++ yield [ ++ ['id' => 'foo', 'class' => 'bar', 'onclick' => 'alert("XSS")', 'href' => 'javascript:alert("XSS")'], ++ [], ++ false, ++ ['id' => 'foo', 'class' => 'bar'], ++ ]; ++ ++ // No allow list; unsafe links allowed ++ yield [ ++ ['id' => 'foo', 'class' => 'bar', 'onclick' => 'alert("XSS")', 'href' => 'javascript:alert("XSS")'], ++ [], ++ true, ++ ['id' => 'foo', 'class' => 'bar', 'href' => 'javascript:alert("XSS")'], ++ ]; ++ ++ // Allow list; unsafe links disallowed ++ yield [ ++ ['id' => 'foo', 'class' => 'bar', 'onclick' => 'alert("XSS")', 'href' => 'javascript:alert("XSS")'], ++ ['id', 'onclick', 'href'], ++ false, ++ ['id' => 'foo', 'onclick' => 'alert("XSS")'], ++ ]; ++ ++ // Allow list; unsafe links allowed ++ yield [ ++ ['id' => 'foo', 'class' => 'bar', 'onclick' => 'alert("XSS")', 'href' => 'javascript:alert("XSS")'], ++ ['id', 'onclick', 'href'], ++ true, ++ ['id' => 'foo', 'onclick' => 'alert("XSS")', 'href' => 'javascript:alert("XSS")'], ++ ]; ++ ++ // Allow list blocks all ++ yield [ ++ ['id' => 'foo', 'class' => ''], ++ ['style'], ++ false, ++ [], ++ ]; ++ ++ // Can't use weird casing to bypass allowlist or 'on*' restriction ++ yield [ ++ ['ID' => 'foo', 'oNcLiCk' => 'alert("XSS")'], ++ ['id', 'class'], ++ false, ++ [], ++ ]; ++ } + } diff -Nru php-league-commonmark-2.3.9/debian/patches/0003-Add-regression-test.patch php-league-commonmark-2.3.9/debian/patches/0003-Add-regression-test.patch --- php-league-commonmark-2.3.9/debian/patches/0003-Add-regression-test.patch 1970-01-01 00:00:00.000000000 +0000 +++ php-league-commonmark-2.3.9/debian/patches/0003-Add-regression-test.patch 2026-03-26 07:15:50.000000000 +0000 @@ -0,0 +1,42 @@ +From: Colin O'Dell +Date: Thu, 5 Mar 2026 07:22:58 -0500 +Subject: Add regression test + +Origin: upstream, https://github.com/thephpleague/commonmark/commit/f6e74434dd1a91f195f80cb0184b746a4187272a +--- + .../DisallowedRawHtml/DisallowedRawHtmlRendererTest.php | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/tests/unit/Extension/DisallowedRawHtml/DisallowedRawHtmlRendererTest.php b/tests/unit/Extension/DisallowedRawHtml/DisallowedRawHtmlRendererTest.php +index 968d780..af25950 100644 +--- a/tests/unit/Extension/DisallowedRawHtml/DisallowedRawHtmlRendererTest.php ++++ b/tests/unit/Extension/DisallowedRawHtml/DisallowedRawHtmlRendererTest.php +@@ -71,6 +71,16 @@ final class DisallowedRawHtmlRendererTest extends TestCase + yield [''), ++ new Embed('//example.com/path'), + ]; + + $inner = $this->createMock(EmbedAdapterInterface::class); diff -Nru php-league-commonmark-2.3.9/debian/patches/series php-league-commonmark-2.3.9/debian/patches/series --- php-league-commonmark-2.3.9/debian/patches/series 2023-02-15 17:36:26.000000000 +0000 +++ php-league-commonmark-2.3.9/debian/patches/series 2026-03-26 07:15:50.000000000 +0000 @@ -1 +1,5 @@ 0001-Skip-tests-relying-on-packages-unavailable-in-Debian.patch +0002-Fix-XSS-in-AttributesExtension.patch +0003-Add-regression-test.patch +0004-Fix-DisallowedRawHtml-bypass-via-newline-tab-in-tag-.patch +0005-Fix-DomainFilteringAdapter-hostname-boundary-bypass.patch