Sep 2, 2026·7 min read·4 visits
Unauthenticated Denial of Service vulnerability in league/commonmark via algorithmic complexity flaws in SmartPunct and Attributes extensions.
GHSA-JJV6-8J6V-6J52 details multiple algorithmic complexity issues in the SmartPunct and Attributes extensions of the league/commonmark PHP library, leading to high CPU consumption and Denial of Service (DoS) when parsing pathological Markdown inputs.
The vulnerability exists in the league/commonmark library, which is a widely used Markdown parser for PHP. The flaw affects the SmartPunct and Attributes extensions, which are frequently enabled components of the parser. These extensions are responsible for converting plain punctuation characters into typographically correct curly equivalents and parsing inline or block attributes respectively.
An attacker can exploit this vulnerability by submitting crafted Markdown documents with pathological input structures. These structures force the parser into highly inefficient execution loops, leading to quadratic time ($O(N^2)$ or $O(K^2)$) complexity and severe memory utilization. Because the Markdown conversion process typically happens on the server side in response to user-generated input, this can result in instantaneous CPU exhaustion and application Denial of Service.
This vulnerability is tracked under the GitHub Security Advisory ID GHSA-JJV6-8J6V-6J52. There is no official CVE identifier assigned to this flaw, meaning standard CVE-based monitoring systems do not list it. The advisory represents a high availability risk for any PHP application hosting untrusted Markdown rendering.
The vulnerability stems from three distinct algorithmic inefficiencies within the library's AST traversal and node manipulation routines. The first issue lies in the SmartPunct extension's AdjacentTextMerger::mergeIfNeeded method, which is invoked to merge neighboring text elements during AST optimization. During the merge, PHP's Copy-on-Write (COW) memory management is triggered repeatedly because string concatenation is performed on a local variable that aliases the node's original literal property, forcing the Zend Engine to duplicate the entire buffer on each concatenation.
The second issue involves the Attributes extension's sibling scanning helper findTargetAndDirection(). When processing a document containing a dense list of contiguous attribute blocks without valid targets, the parser traverses the remaining sibling chain from scratch for every single attribute node. Since this traversal repeats for all $K$ attribute elements in the chain, the traversal operation scales quadratically as $O(K^2)$.
The third issue resides in AttributesHelper::mergeAttributes(), which parses and resolves CSS classes (e.g., {.class-name}). To merge class lists targeting the same node, the helper repetitively retrieves the target's existing class string, splits it into an array, appends the new classes, deduplicates them, and joins them back. Performing this sequence of conversions repeatedly for each successive class definition targeting a single node results in quadratic execution time.
In the SmartPunct extension, the vulnerable code merges adjacent text nodes using an external local variable $s. The assignment $s = $first->getLiteral() shares the reference with the original object, and the subsequent $s .= $node->getLiteral() forces a full string copy. The fixed code eliminates the local variable entirely, using $first->append($node->getLiteral()) to modify the object's property directly, allowing PHP to optimize memory allocation in-place.
// Vulnerable Code: SmartPunct merging
$s = $first->getLiteral();
$node = $first->next();
$stop = $last->next();
while ($node !== $stop && $node instanceof Text) {
$s .= $node->getLiteral(); // COW penalty here
$unlink = $node;
$node = $node->next();
$unlink->detach();
}
$first->setLiteral($s);// Patched Code: SmartPunct merging
$node = $first->next();
$stop = $last->next();
while ($node !== $stop && $node instanceof Text) {
$first->append($node->getLiteral()); // Optimized in-place append
$unlink = $node;
$node = $node->next();
$unlink->detach();
}In the Attributes extension, the patch introduces an SplObjectStorage lookup cache in AttributesListener named $resolved to store pre-computed targets. This stops repetitive walks over the sibling chain. Additionally, class compilation is deferred using a $pending array keyed by the target's unique object ID, executing string operations only once at the end of the parsing process instead of at every single iteration.
Exploiting these issues requires no authentication and is achieved by sending structured Markdown input to any application endpoint that parses user-supplied text. To exploit the SmartPunct vulnerability, an attacker must generate a payload consisting of a large sequence of characters interspersed with unclosed quotation marks. The parser attempts to replace these unpaired quotes with typographically stylized versions, executing the inefficient concatenation loop on thousands of adjacent nodes.
// Unpaired Smart Quotes Payload Generator
$payload = str_repeat(str_repeat('a', 63) . '" ', 64000);To exploit the Attributes sibling scanning inefficiency, an attacker can supply adjacent attribute blocks combined with link references. The parser strips the link definitions, leaving contiguous attribute blocks that have no direct target, which triggers the repetitive sibling traversal routine.
// Adjacent Attribute Blocks Payload Generator
$payload = str_repeat("{#a}\n[a]: u\n", 16000);To exploit the class merging vulnerability, an attacker can supply long chains of block-level or inline attribute markers applying CSS classes to a single element. Because the parser continuously splits and joins the class string, processing a sequence of 32,000 class declarations will fully exhaust the execution timeout and memory limits of standard PHP environments.
// Inline Class Attributes Payload Generator
$payload = str_repeat('{.c}', 32000);The consequence of triggering these flaws is immediate resource exhaustion of the PHP execution thread. Because PHP is single-threaded per request, a single malicious HTTP request processing one of these pathological inputs will lock up a CPU core. If multiple requests are sent concurrently, the entire PHP-FPM pool or web server worker pool can be exhausted rapidly, rendering the hosting application completely unresponsive to legitimate traffic.
Depending on server configuration, PHP memory limits might be reached before the maximum execution time expires. However, because memory allocation occurs recursively and sequentially inside Zend Engine, the memory footprint increases rapidly, leading to Out of Memory (OOM) crashes of individual worker processes. This increases the load on the supervisor process to spawn new workers, compounding the performance degradation.
This vulnerability has a High severity profile. Although it does not result in unauthorized data exposure or remote code execution, the ease of exploitation and the potential to cause a complete service outage with a small input payload makes it a severe security risk for public-facing CMS platforms, forums, and documentation sites.
The recommended mitigation is to upgrade league/commonmark to version 2.9.1 or higher. This update introduces the algorithmic fixes, changing the runtime of document processing from quadratic to linear. To apply the patch, execute the appropriate Composer package manager command.
composer update league/commonmarkIf updating the library is not immediately possible, applications can work around the issue by disabling the affected extensions. This can be accomplished by removing or commenting out the registration calls for SmartPunctExtension and AttributesExtension inside the MarkdownConverter initialization sequence.
Organizations can also implement temporary detection and block rules at the Web Application Firewall (WAF) layer. Regular expressions can inspect incoming HTTP POST bodies for repetitive patterns of unclosed quotes or extremely high densities of curly brace attribute syntax. While this can serve as an interim defense, patching the library remains the only definitive remediation against variant bypasses.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
league/commonmark thephpleague | < 2.9.1 | 2.9.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 / CWE-1333 |
| Attack Vector | Network (Unauthenticated) |
| CVSS v3.1 Score | 7.5 (High) |
| Exploit Status | Proof of Concept (PoC) available |
| CISA KEV Status | Not Listed |
| Impact | Denial of Service (DoS) via CPU and Memory Exhaustion |
The software does not properly control the allocation and maintenance of a limited resource, enabling an actor to influence the amount of resources consumed, leading to Denial of Service.
The league/commonmark library is subject to multiple denial of service vulnerabilities. These stem from three independent algorithmic complexity weaknesses in Markdown parsing: regular expression backtracking, reference link normalization, and delimiter processing. Remote, unauthenticated attackers can exploit these flaws by submitting crafted Markdown input to exhaust CPU execution resources, leading to application-wide thread exhaustion.
An inconsistency in whitespace handling between the PCRE regex engine, PHP's native trim function, and web browsers allows unauthenticated attackers to bypass XSS protections in the league/commonmark AttributesExtension by injecting a Form Feed (U+000C) control character.
An Untrusted Search Path (CWE-426) vulnerability exists in the Natural Language Toolkit (NLTK) library when executing the Graphviz 'dot' utility. Because the library fails to enforce absolute paths when executing external commands, local attackers can plant a malicious binary named 'dot' inside the current working directory. The library then executes the malicious binary, resulting in local arbitrary code execution under the context of the running Python process.
An algorithmic complexity vulnerability (CWE-407) in the AttributesExtension of league/commonmark allows unauthenticated remote attackers to cause CPU exhaustion and Denial of Service (DoS) via crafted Markdown payloads containing adjacent or consecutive attributes.
A stored Cross-Site Scripting (XSS) vulnerability exists in sanitize-html from version 1.9.0 up to 2.17.6. The flaw permits attackers to bypass scheme-policy enforcement using SVG SMIL animation elements targeting URL attributes with semicolon-separated URI lists.
An algorithmic complexity vulnerability in the python sqlparse library versions before 0.6.0 allows an attacker to cause high CPU usage and denial of service via a crafted SQL statement during formatting.