{"id":"CVE-2026-71488","aliases":["CLSA-2026-1788257350","CLSA-2026-1788257456","CLSA-2026-1788257590","DEBIAN-CVE-2026-71488","EUVD-2026-54143","GHSA-2q4p-g7hv-5rgv","GHSA-g2gp-3wwq-f4ph","GHSA-jfm3-95jq-q3rf","GHSA-mh25-x5hq-wrqp","GHSA-mj63-m3rc-8ppr","UBUNTU-CVE-2026-71488"],"status":"published","title":"league/commonmark: Quadratic-time denial of service when parsing crafted Markdown","description":"league/commonmark is a PHP library for parsing and rendering CommonMark Markdown. From 0.6.0 until 2.9.0, specially crafted Markdown lines can cause the parser to have quadratic time complexity when converting, because several parsing paths repeatedly rescan growing portions of a line to translate between character positions and byte positions, and the Autolink extension can also copy and validate the remaining line at every URL-like prefix, allowing an attacker who can submit Markdown for conversion to consume disproportionate CPU time with a comparatively small request. This issue is fixed in 2.9.0.","severity":{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-12","score":0.0063,"percentile":0.5068,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-1050","CWE-405","CWE-407"],"published":"2026-08-06T20:37:17Z","modified":"2026-10-28T02:30:41Z","fixes":[{"ecosystem":"Packagist","package":"league/commonmark","fixed_in":["2.9.0"],"sources":["ghsa","osv"]},{"ecosystem":"Debian:14","package":"php-league-commonmark","fixed_in":["2.9.0-1"],"sources":["osv"]}],"affected":[{"source":"ghsa","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.6.0"},{"fixed":"2.9.0"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.5.0"},{"fixed":"2.9.0"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.5.0"},{"fixed":"2.9.0"}]}]},{"source":"ghsa","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0"},{"fixed":"2.9.0"}]}]},{"source":"osv","ecosystem":"TuxCare:Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.6.7"},{"fixed":"1.6.7-p4+tuxcare"}]}],"versions":["1.6.7","1.6.7-p1+tuxcare","1.6.7-p2+tuxcare","1.6.7-p3+tuxcare"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.8.2"},{"fixed":"2.8.2-p2+tuxcare"}]}],"versions":["2.8.2"],"bundled":2},{"source":"osv","ecosystem":"TuxCare:Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.7.1"},{"fixed":"2.7.1-p2+tuxcare"}]}],"versions":["2.7.1","2.7.1-p1+tuxcare"],"bundled":2},{"source":"osv","ecosystem":"Debian:12","package":"php-league-commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.10.0-1","2.10.1-1","2.10.3-1","2.10.4-1","2.3.9-1","2.3.9-1+deb12u1","2.4.0-1","2.4.1-1","2.4.2-1","2.4.2-2","2.5.0-1","2.5.1-1","2.5.3-1","2.6.0-1","2.6.1-1","2.6.1-2","2.6.2-1","2.7.0-1","2.7.1-1","2.7.1-2","2.8.0-1","2.8.1-1","2.8.2-1","2.8.2-2","2.8.3-1","2.9.0-1"]},{"source":"osv","ecosystem":"Debian:13","package":"php-league-commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["2.10.0-1","2.10.1-1","2.10.3-1","2.10.4-1","2.7.0-1","2.7.0-1+deb13u1","2.7.1-1","2.7.1-2","2.8.0-1","2.8.1-1","2.8.2-1","2.8.2-2","2.8.3-1","2.9.0-1"]},{"source":"osv","ecosystem":"Debian:14","package":"php-league-commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.9.0-1"}]}],"versions":["2.7.0-1","2.7.1-1","2.7.1-2","2.8.0-1","2.8.1-1","2.8.2-1","2.8.2-2","2.8.3-1"]},{"source":"osv","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.6.0"},{"fixed":"2.9.0"}]}],"versions":["0.10.0","0.11.0","0.11.1","0.11.2","0.11.3","0.12.0","0.13.0","0.13.1","0.13.2","0.13.3","0.13.4","0.14.0","0.15.0","0.15.1","0.15.2","0.15.3","0.15.4","0.15.5","0.15.6","0.15.7","0.16.0","0.17.0","0.17.1","0.17.2","0.17.3","0.17.4","0.17.5","0.18.0","0.18.1","0.18.2","0.18.3","0.18.4","0.18.5","0.19.0","0.19.1","0.19.2","0.19.3","0.6.0","0.6.1","0.7.0","0.7.1","0.7.2","0.8.0","0.9.0","1.0.0","1.0.0-beta1","1.0.0-beta2","1.0.0-beta3","1.0.0-beta4","1.0.0-rc1","1.1.0","1.1.1","1.1.2","1.1.3","1.2.0","1.2.1","1.2.2","1.3.0","1.3.1","1.3.2","1.3.3","1.3.4","1.4.0","1.4.1","1.4.2","1.4.3","1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.5.5","1.5.6","1.5.7","1.5.8","1.6.0","1.6.1","1.6.2","1.6.3","1.6.4","1.6.5","1.6.6","1.6.7","2.0.0","2.0.0-beta1","2.0.0-beta2","2.0.0-beta3","2.0.0-rc1","2.0.0-rc2","2.0.1","2.0.2","2.0.3","2.0.4","2.1.0","2.1.1","2.1.2","2.1.3","2.2.0","2.2.1","2.2.2","2.2.3","2.2.4","2.2.5","2.3.0","2.3.1","2.3.2","2.3.3","2.3.4","2.3.5","2.3.6","2.3.7","2.3.8","2.3.9","2.4.0","2.4.1","2.4.2","2.4.3","2.4.4","2.5.0","2.5.1","2.5.2","2.5.3","2.6.0","2.6.1","2.6.2","2.7.0","2.7.1","2.8.0","2.8.1","2.8.2","2.8.3"]},{"source":"osv","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.5.0"},{"fixed":"2.9.0"}]}],"versions":["1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.5.5","1.5.6","1.5.7","1.5.8","1.6.0","1.6.1","1.6.2","1.6.3","1.6.4","1.6.5","1.6.6","1.6.7","2.0.0","2.0.0-beta1","2.0.0-beta2","2.0.0-beta3","2.0.0-rc1","2.0.0-rc2","2.0.1","2.0.2","2.0.3","2.0.4","2.1.0","2.1.1","2.1.2","2.1.3","2.2.0","2.2.1","2.2.2","2.2.3","2.2.4","2.2.5","2.3.0","2.3.1","2.3.2","2.3.3","2.3.4","2.3.5","2.3.6","2.3.7","2.3.8","2.3.9","2.4.0","2.4.1","2.4.2","2.4.3","2.4.4","2.5.0","2.5.1","2.5.2","2.5.3","2.6.0","2.6.1","2.6.2","2.7.0","2.7.1","2.8.0","2.8.1","2.8.2","2.8.3"]},{"source":"osv","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"1.5.0"},{"fixed":"2.9.0"}]}],"versions":["1.5.0","1.5.1","1.5.2","1.5.3","1.5.4","1.5.5","1.5.6","1.5.7","1.5.8","1.6.0","1.6.1","1.6.2","1.6.3","1.6.4","1.6.5","1.6.6","1.6.7","2.0.0","2.0.0-beta1","2.0.0-beta2","2.0.0-beta3","2.0.0-rc1","2.0.0-rc2","2.0.1","2.0.2","2.0.3","2.0.4","2.1.0","2.1.1","2.1.2","2.1.3","2.2.0","2.2.1","2.2.2","2.2.3","2.2.4","2.2.5","2.3.0","2.3.1","2.3.2","2.3.3","2.3.4","2.3.5","2.3.6","2.3.7","2.3.8","2.3.9","2.4.0","2.4.1","2.4.2","2.4.3","2.4.4","2.5.0","2.5.1","2.5.2","2.5.3","2.6.0","2.6.1","2.6.2","2.7.0","2.7.1","2.8.0","2.8.1","2.8.2","2.8.3"]},{"source":"osv","ecosystem":"Packagist","package":"league/commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"2.0.0"},{"fixed":"2.9.0"}]}],"versions":["2.0.0","2.0.1","2.0.2","2.0.3","2.0.4","2.1.0","2.1.1","2.1.2","2.1.3","2.2.0","2.2.1","2.2.2","2.2.3","2.2.4","2.2.5","2.3.0","2.3.1","2.3.2","2.3.3","2.3.4","2.3.5","2.3.6","2.3.7","2.3.8","2.3.9","2.4.0","2.4.1","2.4.2","2.4.3","2.4.4","2.5.0","2.5.1","2.5.2","2.5.3","2.6.0","2.6.1","2.6.2","2.7.0","2.7.1","2.8.0","2.8.1","2.8.2","2.8.3"]},{"source":"osv","ecosystem":"Ubuntu:16.04:LTS","package":"markdown","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.1-7","1.0.1-8"]},{"source":"osv","ecosystem":"Ubuntu:18.04:LTS","package":"markdown","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.1-9","1.0.1-10"]},{"source":"osv","ecosystem":"Ubuntu:20.04:LTS","package":"markdown","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.1-10"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.9.1-3"]},{"source":"osv","ecosystem":"Ubuntu:22.04:LTS","package":"markdown","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.1-10.1"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.9.1-4","0.9.1-5"]},{"source":"osv","ecosystem":"Ubuntu:24.04:LTS","package":"markdown","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.1-12"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.9.1-8build1"]},{"source":"osv","ecosystem":"Ubuntu:26.10","package":"markdown","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.1-14"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"commonmark","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["0.9.1-8","0.9.1-8build1"]},{"source":"osv","ecosystem":"Ubuntu:26.04:LTS","package":"markdown","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"}]}],"versions":["1.0.1-14"]}],"products":[{"vendor":"thephpleague","product":"commonmark"}],"references":[{"url":"https://github.com/thephpleague/commonmark/security/advisories/GHSA-2q4p-g7hv-5rgv","tags":["x_refsource_CONFIRM","advisory","web","report"]},{"url":"https://github.com/thephpleague/commonmark/commit/a6ef6cdc308dfa39a34239c35818e75892a0e6a8","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/thephpleague/commonmark/commit/a70979ea0d7d3377bd7127536748454a922bf5eb","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/thephpleague/commonmark/commit/c97b02e5e652b992033b93ba5d6182f706343fc6","tags":["x_refsource_MISC","fix","web","report"]},{"url":"https://github.com/thephpleague/commonmark/releases/tag/2.9.0","tags":["x_refsource_MISC","web","report"]},{"url":"https://github.com/advisories/GHSA-2q4p-g7hv-5rgv"},{"url":"https://github.com/thephpleague/commonmark/security/advisories/GHSA-g2gp-3wwq-f4ph","tags":["web"]},{"url":"https://github.com/thephpleague/commonmark/commit/2d4c0fafa62501be919262064cffa6d71687430b","tags":["web"]},{"url":"https://github.com/advisories/GHSA-g2gp-3wwq-f4ph"},{"url":"https://github.com/thephpleague/commonmark/security/advisories/GHSA-jfm3-95jq-q3rf","tags":["web"]},{"url":"https://github.com/thephpleague/commonmark/commit/66028124a17ba193da7b11cc3dfda92df21bfbf4","tags":["web"]},{"url":"https://github.com/advisories/GHSA-jfm3-95jq-q3rf"},{"url":"https://github.com/thephpleague/commonmark/security/advisories/GHSA-mj63-m3rc-8ppr","tags":["web"]},{"url":"https://github.com/thephpleague/commonmark/commit/b5ac8c3947ca81844e85a09c7e0a5b4148bde2e1","tags":["web"]},{"url":"https://github.com/advisories/GHSA-mj63-m3rc-8ppr"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/71xxx/CVE-2026-71488.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-71488","tags":["advisory"]},{"url":"https://security-tracker.debian.org/tracker/CVE-2026-71488","tags":["advisory"]},{"url":"https://github.com/thephpleague/commonmark","tags":["package"]},{"url":"https://ubuntu.com/security/CVE-2026-71488","tags":["report"]},{"url":"https://www.cve.org/CVERecord?id=CVE-2026-71488","tags":["report"]}],"sources":{"cve":[{"id":"CVE-2026-71488","title":"league/commonmark: Quadratic-time denial of service when parsing crafted Markdown","description":"league/commonmark is a PHP library for parsing and rendering CommonMark Markdown. From 0.6.0 until 2.9.0, specially crafted Markdown lines can cause the parser to have quadratic time complexity when converting, because several parsing paths repeatedly rescan growing portions of a line to translate between character positions and byte positions, and the Autolink extension can also copy and validate the remaining line at every URL-like prefix, allowing an attacker who can submit Markdown for conversion to consume disproportionate CPU time with a comparatively small request. This issue is fixed in 2.9.0.","status":"published","published":"2026-08-06T20:37:17.488Z","modified":"2026-08-07T17:17:05.299Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"cna"}],"cwes":["CWE-407","CWE-1050"],"updated_at":"2026-11-02T14:19:49.199185Z"}],"euvd":[{"id":"EUVD-2026-54143","description":"league/commonmark is a PHP library for parsing and rendering CommonMark Markdown. From 0.6.0 until 2.9.0, specially crafted Markdown lines can cause the parser to have quadratic time complexity when converting, because several parsing paths repeatedly rescan growing portions of a line to translate between character positions and byte positions, and the Autolink extension can also copy and validate the remaining line at every URL-like prefix, allowing an attacker who can submit Markdown for conversion to consume disproportionate CPU time with a comparatively small request. This issue is fixed in 2.9.0.","status":"published","published":"2026-08-06T20:37:17Z","modified":"2026-08-07T17:17:05Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T18:02:06.930016Z"}],"ghsa":[{"id":"GHSA-2q4p-g7hv-5rgv","title":"league/commonmark: Quadratic-time denial of service when parsing crafted Markdown","description":"### Impact\n\nAffected versions of `league/commonmark` can have quadratic time complexity when parsing specially crafted Markdown lines. In practical terms, doubling the length of an affected line can make the parser perform roughly four times as much work. The parser identifies locations using character positions, but regular-expression matches report byte positions. These positions differ when a UTF-8 character uses more than one byte. Several parsing paths repeatedly rescan growing portions of the line to translate between the two positions. The Autolink extension can also copy and validate the remaining line at every URL-like prefix.\n\nIn current 2.x releases, a single non-ASCII character anywhere on a line can place that whole line on the slower multibyte path. An attacker can combine it with a long run of leading whitespace or repeated Markdown punctuation, causing increasingly large rescans. When the Autolink extension is enabled, repeated URL-like prefixes provide another trigger, even on ASCII-only lines. Each trigger fits within one long line, so complex Markdown structure is unnecessary.\n\nAn attacker who can submit Markdown for conversion can use a comparatively small request to consume disproportionate CPU time and allocation activity. Repeated or concurrent requests can occupy all available PHP workers and prevent legitimate requests from completing. The core paths affect `CommonMarkConverter`, `GithubFlavoredMarkdownConverter`, and custom environments. The autolink-specific path affects applications using `AutolinkExtension` or `GithubFlavoredMarkdownExtension`. Applications that process only trusted Markdown are not remotely exploitable. The impact is limited to availability: it does not disclose data, change rendered output, or bypass rendering restrictions. Settings such as `html_input` and `allow_unsafe_links` do not mitigate the issue because the expensive work occurs before rendering.\n\n### Patches\n\nThe issue is patched in `2.9.0` and later. Starting in that release, the parser records UTF-8 character-to-byte positions incrementally, converts ordered regular-expression match positions without restarting from the beginning of the line, and matches autolinks against the original line instead of copying every remaining suffix. The affected work then grows in direct proportion to the input size while preserving existing Markdown output and configuration behavior. Versions from `0.6.0` through `2.8.3` are affected. The 0.x and 1.x release lines are no longer supported, so their users must upgrade to `2.9.0` or later.\n\n### Workarounds\n\nIf you cannot upgrade immediately, reject or truncate inputs with excessively long individual lines before passing them to the converter. A total request-size limit is also useful, but a per-line limit is important because every demonstrated trigger fits on one line. Choose limits appropriate for the application and enforce them before Markdown parsing begins. Restricting conversion to trusted users, applying strict execution-time limits, rate-limiting requests, and limiting concurrent conversions can further reduce exposure, but these measures are not complete substitutes for upgrading.\n\nDisabling `AutolinkExtension` and avoiding `GithubFlavoredMarkdownExtension` removes the autolink-specific trigger, but the core multibyte parsing paths remain reachable in the standard parser. Existing nesting, delimiter, raw-HTML, and unsafe-link configuration options do not eliminate all affected paths. Applications that must continue processing untrusted Markdown should therefore enforce input limits even when autolinking is disabled.","status":"published","published":"2026-08-06T20:37:20Z","modified":"2026-08-06T20:37:21Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-407","CWE-1050"],"updated_at":"2026-11-02T14:40:57.999375Z"},{"id":"GHSA-g2gp-3wwq-f4ph","title":"league/commonmark: Denial of service via adjacent inline attribute blocks","description":"### Impact\n\nWith the Attributes extension enabled, `AttributesListener::findTargetAndDirection()` resolves each attribute node's target by walking outward through its siblings. For a run of N adjacent inline attribute blocks placed at the start of a block (with nothing to their left), each node scans the **entire** sibling list to the far-right end before giving up and falling back to the parent. Each resolution is therefore Θ(N) and the whole run is **Θ(N²)**.\n\nReaching the path requires `AttributesExtension` (opt-in, but first-party: `League\\CommonMark\\Extension\\Attributes\\AttributesExtension`). No other configuration matters — the quadratic walk runs unconditionally during parsing and is **not** gated by the `attributes/allow` allow-list, the `on*` hardening added in 2.7.0, or `allow_unsafe_links`. An unauthenticated attacker can submit a **~32 KB** input (`{#a}` repeated 8,000 times) that takes **over 5 seconds** to convert, with time growing quadratically in input length — a cheap denial of service. Availability impact only. **The Attributes extension was introduced in 1.5.0 (May 2020) with this outward-walk resolver present from the first commit, so all releases from 1.5.0 onward (including every 2.x) are affected.**\n\n### Workarounds\n\nThere is no library-level configuration that gates the quadratic walk. Integrators who cannot upgrade can only reduce exposure indirectly:\n\n- **Disable the Attributes extension** for untrusted input, or\n- **Impose a strict maximum input length before conversion** — noting that because the cost is quadratic, even a modest cap must be small to meaningfully bound worst-case CPU.\n\nUpgrading to a release containing the fix is recommended.","status":"published","published":"2026-08-06T20:39:52Z","modified":"2026-08-06T20:39:53Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-407"],"updated_at":"2026-11-02T14:40:57.999375Z"},{"id":"GHSA-jfm3-95jq-q3rf","title":"league/commonmark:  Denial of service via duplicate footnote definitions","description":"### Impact\n\nThe Footnote extension records one backref per footnote *reference* and then appends the **entire** backref list for **every** footnote *definition* block in the document, without ever de-duplicating or removing repeated definitions of the same label (`GatherFootnotesListener`, populated by `NumberFootnotesListener`). A document that references a single label N times and also supplies N duplicate `[^a]:` definitions of that label therefore produces **N × N** `FootnoteBackref` nodes, so output size, parse time, and peak memory are all **O(N²)**.\n\nReaching the vulnerable path requires `FootnoteExtension` to be registered on the `Environment`. This is opt-in, but is a commonly enabled GFM-style feature; no other non-default configuration is required. An unauthenticated attacker can expand a **~10 KB** request into a **~62 MB** HTML response, **~3 s** of CPU, and **~440 MB** of peak memory — enough to OOM-kill a default 128 MB PHP worker and deny service. Availability impact only; no confidentiality or integrity effect. **The Footnote extension was introduced in 1.5.0 (May 2020) with this backref logic present from the first commit, so all releases from 1.5.0 onward (including every 2.x through 2.8.x) are affected.**\n\n### Workarounds\n\nThere is no library-level option to cap the number of footnotes, references, or definitions, so no configuration switch prevents the amplification. Integrators who cannot upgrade should:\n\n- **Disable the Footnote extension** for untrusted input, or\n- **Enforce a strict input-size limit before conversion** — but note this is a weak control here, since the ~10 KB payload that already triggers the 62 MB / ~440 MB blowup is well within typical request-body limits, so any cap must be aggressively small to help.\n\nUpgrading to the patched release is the recommended remediation.","status":"published","published":"2026-08-06T20:40:53Z","modified":"2026-08-06T20:42:11Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-407"],"updated_at":"2026-11-02T14:40:57.999375Z"},{"id":"GHSA-mj63-m3rc-8ppr","title":"league/commonmark: Denial of service via deeply nested XML output","description":"### Impact\n\n`XmlRenderer` pretty-prints XML by emitting depth-proportional indentation whitespace for **every** opening and closing tag. For a tree of depth n, the indentation alone sums to **O(n²)** bytes of output (and corresponding memory), reachable through `MarkdownToXmlConverter` — e.g. `str_repeat('\u003e ', $depth) . \"x\\n\"`, a single line of nested blockquotes — or through a direct `XmlRenderer::renderDocument()` call on an attacker-influenced AST.\n\nThis affects applications that convert untrusted Markdown to XML, which is an **opt-in** output path. The parser's `max_nesting_level` bounds the depth of *parser-created* trees, but its default is high enough to reach damaging sizes, can be raised by the host application, and does not constrain custom or programmatically built ASTs handed straight to the renderer. The result is a memory / output-size amplification rather than a hard crash, which is why this issue is rated **Medium** rather than High. No confidentiality or integrity impact. XML rendering was introduced in 2.0.0 (first shipped in 2.0.0-beta1, June 2021) and has emitted depth-proportional indentation ever since, so all 2.x releases are affected (verified against 2.8.x, clean upstream `1902f60f`). 1.x has no XML renderer and is not affected.\n\n### Workarounds\n\nApplications converting untrusted Markdown to XML should:\n\n- **Lower `max_nesting_level`** to a conservative value appropriate to expected content, so the parser refuses to build extremely deep trees. This is the most direct lever for parser-produced ASTs, but does not protect trees built programmatically and passed straight to `XmlRenderer`.\n- **Cap input size before conversion**, since the amplification is driven by input-proportional depth.\n- **Constrain XML consumers** with memory / output-size limits (and streaming or size caps on any downstream XML parser or storage) so one request cannot allocate unbounded output.\n- **Prefer HTML rendering** for untrusted content where XML is not strictly required — the HTML renderer does not emit depth-proportional indentation and is not subject to this amplification.","status":"published","published":"2026-08-06T20:42:54Z","modified":"2026-08-06T20:42:56Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"}],"cwes":["CWE-405"],"updated_at":"2026-11-02T14:40:57.999375Z"}],"nvd":[{"id":"CVE-2026-71488","description":"league/commonmark is a PHP library for parsing and rendering CommonMark Markdown. From 0.6.0 until 2.9.0, specially crafted Markdown lines can cause the parser to have quadratic time complexity when converting, because several parsing paths repeatedly rescan growing portions of a line to translate between character positions and byte positions, and the Autolink extension can also copy and validate the remaining line at every URL-like prefix, allowing an attacker who can submit Markdown for conversion to consume disproportionate CPU time with a comparatively small request. This issue is fixed in 2.9.0.","status":"published","published":"2026-08-06T22:18:31.893Z","modified":"2026-10-24T15:10:00.19Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high","assessor":"secondary"}],"cwes":["CWE-407","CWE-1050"],"updated_at":"2026-11-02T14:12:35.386166Z"}],"osv":[{"id":"CVE-2026-71488","title":"league/commonmark: Quadratic-time denial of service when parsing crafted Markdown","description":"league/commonmark is a PHP library for parsing and rendering CommonMark Markdown. From 0.6.0 until 2.9.0, specially crafted Markdown lines can cause the parser to have quadratic time complexity when converting, because several parsing paths repeatedly rescan growing portions of a line to translate between character positions and byte positions, and the Autolink extension can also copy and validate the remaining line at every URL-like prefix, allowing an attacker who can submit Markdown for conversion to consume disproportionate CPU time with a comparatively small request. This issue is fixed in 2.9.0.","status":"published","published":"2026-08-06T20:37:17.488Z","modified":"2026-10-28T02:30:41.550349284Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-1050","CWE-407"],"updated_at":"2026-11-02T15:45:15.164658Z"},{"id":"DEBIAN-CVE-2026-71488","description":"league/commonmark is a PHP library for parsing and rendering CommonMark Markdown. From 0.6.0 until 2.9.0, specially crafted Markdown lines can cause the parser to have quadratic time complexity when converting, because several parsing paths repeatedly rescan growing portions of a line to translate between character positions and byte positions, and the Autolink extension can also copy and validate the remaining line at every URL-like prefix, allowing an attacker who can submit Markdown for conversion to consume disproportionate CPU time with a comparatively small request. This issue is fixed in 2.9.0.","status":"published","published":"2026-08-06T22:18:31.893Z","modified":"2026-10-25T09:47:40.743002032Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T15:46:02.094661Z"},{"id":"GHSA-2q4p-g7hv-5rgv","title":"league/commonmark: Quadratic-time denial of service when parsing crafted Markdown","description":"### Impact\n\nAffected versions of `league/commonmark` can have quadratic time complexity when parsing specially crafted Markdown lines. In practical terms, doubling the length of an affected line can make the parser perform roughly four times as much work. The parser identifies locations using character positions, but regular-expression matches report byte positions. These positions differ when a UTF-8 character uses more than one byte. Several parsing paths repeatedly rescan growing portions of the line to translate between the two positions. The Autolink extension can also copy and validate the remaining line at every URL-like prefix.\n\nIn current 2.x releases, a single non-ASCII character anywhere on a line can place that whole line on the slower multibyte path. An attacker can combine it with a long run of leading whitespace or repeated Markdown punctuation, causing increasingly large rescans. When the Autolink extension is enabled, repeated URL-like prefixes provide another trigger, even on ASCII-only lines. Each trigger fits within one long line, so complex Markdown structure is unnecessary.\n\nAn attacker who can submit Markdown for conversion can use a comparatively small request to consume disproportionate CPU time and allocation activity. Repeated or concurrent requests can occupy all available PHP workers and prevent legitimate requests from completing. The core paths affect `CommonMarkConverter`, `GithubFlavoredMarkdownConverter`, and custom environments. The autolink-specific path affects applications using `AutolinkExtension` or `GithubFlavoredMarkdownExtension`. Applications that process only trusted Markdown are not remotely exploitable. The impact is limited to availability: it does not disclose data, change rendered output, or bypass rendering restrictions. Settings such as `html_input` and `allow_unsafe_links` do not mitigate the issue because the expensive work occurs before rendering.\n\n### Patches\n\nThe issue is patched in `2.9.0` and later. Starting in that release, the parser records UTF-8 character-to-byte positions incrementally, converts ordered regular-expression match positions without restarting from the beginning of the line, and matches autolinks against the original line instead of copying every remaining suffix. The affected work then grows in direct proportion to the input size while preserving existing Markdown output and configuration behavior. Versions from `0.6.0` through `2.8.3` are affected. The 0.x and 1.x release lines are no longer supported, so their users must upgrade to `2.9.0` or later.\n\n### Workarounds\n\nIf you cannot upgrade immediately, reject or truncate inputs with excessively long individual lines before passing them to the converter. A total request-size limit is also useful, but a per-line limit is important because every demonstrated trigger fits on one line. Choose limits appropriate for the application and enforce them before Markdown parsing begins. Restricting conversion to trusted users, applying strict execution-time limits, rate-limiting requests, and limiting concurrent conversions can further reduce exposure, but these measures are not complete substitutes for upgrading.\n\nDisabling `AutolinkExtension` and avoiding `GithubFlavoredMarkdownExtension` removes the autolink-specific trigger, but the core multibyte parsing paths remain reachable in the standard parser. Existing nesting, delimiter, raw-HTML, and unsafe-link configuration options do not eliminate all affected paths. Applications that must continue processing untrusted Markdown should therefore enforce input limits even when autolinking is disabled.","status":"published","published":"2026-08-06T20:37:20Z","modified":"2026-08-21T05:21:14.106549823Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-1050","CWE-407"],"updated_at":"2026-11-02T15:46:34.700741Z"},{"id":"GHSA-g2gp-3wwq-f4ph","title":"league/commonmark: Denial of service via adjacent inline attribute blocks","description":"### Impact\n\nWith the Attributes extension enabled, `AttributesListener::findTargetAndDirection()` resolves each attribute node's target by walking outward through its siblings. For a run of N adjacent inline attribute blocks placed at the start of a block (with nothing to their left), each node scans the **entire** sibling list to the far-right end before giving up and falling back to the parent. Each resolution is therefore Θ(N) and the whole run is **Θ(N²)**.\n\nReaching the path requires `AttributesExtension` (opt-in, but first-party: `League\\CommonMark\\Extension\\Attributes\\AttributesExtension`). No other configuration matters — the quadratic walk runs unconditionally during parsing and is **not** gated by the `attributes/allow` allow-list, the `on*` hardening added in 2.7.0, or `allow_unsafe_links`. An unauthenticated attacker can submit a **~32 KB** input (`{#a}` repeated 8,000 times) that takes **over 5 seconds** to convert, with time growing quadratically in input length — a cheap denial of service. Availability impact only. **The Attributes extension was introduced in 1.5.0 (May 2020) with this outward-walk resolver present from the first commit, so all releases from 1.5.0 onward (including every 2.x) are affected.**\n\n### Workarounds\n\nThere is no library-level configuration that gates the quadratic walk. Integrators who cannot upgrade can only reduce exposure indirectly:\n\n- **Disable the Attributes extension** for untrusted input, or\n- **Impose a strict maximum input length before conversion** — noting that because the cost is quadratic, even a modest cap must be small to meaningfully bound worst-case CPU.\n\nUpgrading to a release containing the fix is recommended.","status":"published","published":"2026-08-06T20:39:52Z","modified":"2026-08-06T20:45:15.558862305Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-407"],"updated_at":"2026-11-02T15:46:47.119724Z"},{"id":"GHSA-jfm3-95jq-q3rf","title":"league/commonmark:  Denial of service via duplicate footnote definitions","description":"### Impact\n\nThe Footnote extension records one backref per footnote *reference* and then appends the **entire** backref list for **every** footnote *definition* block in the document, without ever de-duplicating or removing repeated definitions of the same label (`GatherFootnotesListener`, populated by `NumberFootnotesListener`). A document that references a single label N times and also supplies N duplicate `[^a]:` definitions of that label therefore produces **N × N** `FootnoteBackref` nodes, so output size, parse time, and peak memory are all **O(N²)**.\n\nReaching the vulnerable path requires `FootnoteExtension` to be registered on the `Environment`. This is opt-in, but is a commonly enabled GFM-style feature; no other non-default configuration is required. An unauthenticated attacker can expand a **~10 KB** request into a **~62 MB** HTML response, **~3 s** of CPU, and **~440 MB** of peak memory — enough to OOM-kill a default 128 MB PHP worker and deny service. Availability impact only; no confidentiality or integrity effect. **The Footnote extension was introduced in 1.5.0 (May 2020) with this backref logic present from the first commit, so all releases from 1.5.0 onward (including every 2.x through 2.8.x) are affected.**\n\n### Workarounds\n\nThere is no library-level option to cap the number of footnotes, references, or definitions, so no configuration switch prevents the amplification. Integrators who cannot upgrade should:\n\n- **Disable the Footnote extension** for untrusted input, or\n- **Enforce a strict input-size limit before conversion** — but note this is a weak control here, since the ~10 KB payload that already triggers the 62 MB / ~440 MB blowup is well within typical request-body limits, so any cap must be aggressively small to help.\n\nUpgrading to the patched release is the recommended remediation.","status":"published","published":"2026-08-06T20:40:53Z","modified":"2026-08-06T20:45:15.56408473Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"cwes":["CWE-407"],"updated_at":"2026-11-02T15:46:50.336262Z"},{"id":"GHSA-mj63-m3rc-8ppr","title":"league/commonmark: Denial of service via deeply nested XML output","description":"### Impact\n\n`XmlRenderer` pretty-prints XML by emitting depth-proportional indentation whitespace for **every** opening and closing tag. For a tree of depth n, the indentation alone sums to **O(n²)** bytes of output (and corresponding memory), reachable through `MarkdownToXmlConverter` — e.g. `str_repeat('\u003e ', $depth) . \"x\\n\"`, a single line of nested blockquotes — or through a direct `XmlRenderer::renderDocument()` call on an attacker-influenced AST.\n\nThis affects applications that convert untrusted Markdown to XML, which is an **opt-in** output path. The parser's `max_nesting_level` bounds the depth of *parser-created* trees, but its default is high enough to reach damaging sizes, can be raised by the host application, and does not constrain custom or programmatically built ASTs handed straight to the renderer. The result is a memory / output-size amplification rather than a hard crash, which is why this issue is rated **Medium** rather than High. No confidentiality or integrity impact. XML rendering was introduced in 2.0.0 (first shipped in 2.0.0-beta1, June 2021) and has emitted depth-proportional indentation ever since, so all 2.x releases are affected (verified against 2.8.x, clean upstream `1902f60f`). 1.x has no XML renderer and is not affected.\n\n### Workarounds\n\nApplications converting untrusted Markdown to XML should:\n\n- **Lower `max_nesting_level`** to a conservative value appropriate to expected content, so the parser refuses to build extremely deep trees. This is the most direct lever for parser-produced ASTs, but does not protect trees built programmatically and passed straight to `XmlRenderer`.\n- **Cap input size before conversion**, since the amplification is driven by input-proportional depth.\n- **Constrain XML consumers** with memory / output-size limits (and streaming or size caps on any downstream XML parser or storage) so one request cannot allocate unbounded output.\n- **Prefer HTML rendering** for untrusted content where XML is not strictly required — the HTML renderer does not emit depth-proportional indentation and is not subject to this amplification.","status":"published","published":"2026-08-06T20:42:54Z","modified":"2026-08-06T20:45:15.556829535Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","level":"medium"}],"cwes":["CWE-405"],"updated_at":"2026-11-02T15:46:51.811331Z"},{"id":"UBUNTU-CVE-2026-71488","description":"league/commonmark is a PHP library for parsing and rendering CommonMark Markdown. From 0.6.0 until 2.9.0, specially crafted Markdown lines can cause the parser to have quadratic time complexity when converting, because several parsing paths repeatedly rescan growing portions of a line to translate between character positions and byte positions, and the Autolink extension can also copy and validate the remaining line at every URL-like prefix, allowing an attacker who can submit Markdown for conversion to consume disproportionate CPU time with a comparatively small request. This issue is fixed in 2.9.0.","status":"published","published":"2026-08-06T22:18:00Z","modified":"2026-10-17T13:00:46.199823698Z","cvss":[{"version":"3.1","score":7.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H","level":"high"}],"updated_at":"2026-11-02T16:57:03.035847Z"},{"id":"CLSA-2026-1788257350","title":"TuxCare security update for league/commonmark (4 CVEs)","description":"TuxCare rebuilt league/commonmark to address 4 CVEs. Fixed in 1.6.7-p4+tuxcare.","status":"published","published":"2026-09-01T10:09:10Z","modified":"2026-10-15T09:48:00.582192094Z","updated_at":"2026-11-02T15:43:47.591214Z"},{"id":"CLSA-2026-1788257456","title":"TuxCare security update for league/commonmark (6 CVEs)","description":"TuxCare rebuilt league/commonmark to address 6 CVEs. Fixed in 2.8.2-p2+tuxcare.","status":"published","published":"2026-09-01T10:10:56Z","modified":"2026-10-15T09:48:00.493236951Z","updated_at":"2026-11-02T15:43:47.591214Z"},{"id":"CLSA-2026-1788257590","title":"TuxCare security update for league/commonmark (6 CVEs)","description":"TuxCare rebuilt league/commonmark to address 6 CVEs. Fixed in 2.7.1-p2+tuxcare.","status":"published","published":"2026-09-01T10:13:10Z","modified":"2026-10-15T09:48:00.463295018Z","updated_at":"2026-11-02T15:43:47.591214Z"}]}}
