Apr 30, 2026·6 min read·4 visits
Unauthenticated DoS in marked via a 3-byte payload (\t\v\n) causing infinite loops and Out-of-Memory crashes.
The marked Node.js Markdown parser versions 18.0.0 and 18.0.1 contain a critical vulnerability where a specific 3-byte sequence triggers infinite recursion. This flaw leads to rapid memory exhaustion and application denial of service.
The marked library serves as a widely deployed Markdown parser and compiler for Node.js environments. Applications frequently utilize this package to process untrusted user input into HTML output. Versions 18.0.0 and 18.0.1 contain a logic error in the tokenization process that leads to unbounded resource consumption.
The vulnerability is classified as CWE-835 (Loop with Unreachable Exit Condition) and CWE-400 (Uncontrolled Resource Consumption). An unauthenticated attacker can trigger this flaw by submitting a specifically crafted three-byte character sequence. The parser fails to process these characters correctly, entering a recursive loop that allocates memory continuously.
The attack surface includes any application endpoint that accepts user-supplied Markdown and processes it using a vulnerable version of the library. Common examples include comment systems, forum post rendering, and document management applications. The vulnerability requires no non-default configurations or specialized deployment architectures.
Successful exploitation results in rapid heap memory exhaustion within the Node.js process. The application subsequently crashes with an Out-of-Memory (OOM) error, dropping all active connections and rendering the service unavailable.
The root cause exists within the Lexer's legacy ASCII whitespace character processing routines. The vulnerability specifically involves the space tokenizer's regular expression, which evaluates what constitutes a blank line or ignorable spacing. This regex successfully consumes standard spaces and horizontal tabs, but it explicitly excludes the Vertical Tab (\x0b) character.
When the parser processes an indented line starting with a horizontal tab (\x09) followed by a Vertical Tab and a newline, it attempts to route the input through the indented code block rules. The space tokenizer fails to consume the sequence because the Vertical Tab breaks the regex matching logic. The lexer then falls back to the text tokenizer to handle the unparsed characters.
In the vulnerable 18.0.x versions, the fallback logic fails to properly advance the source string pointer (src) when processing this exact character sequence. Because the pointer does not advance, the remaining input string is never reduced in length. The parser subsequently invokes inlineTokens() recursively on the exact same input string.
This creates an infinite loop where the parser continuously generates new token objects and concatenates string metadata. The lack of a terminal condition causes the process to allocate memory on the heap indefinitely. The Node.js garbage collector cannot reclaim this memory because the active recursion stack maintains references to the token objects.
The vulnerability stems from the absence of a progress validation check in the main tokenization loop. The vulnerable implementation processes the src string through various tokenizers, assuming that at least one tokenizer will consume characters and shorten the string. When the specific \t\v\n payload is encountered, this assumption fails.
The maintainers resolved the issue in version 18.0.2 by implementing a robust progress guard within src/Lexer.ts. The patch records the initial length of the string at the beginning of each iteration. After all tokenizers execute, the code compares the new string length against the initial length to verify progress.
// Conceptual representation of the fix in Lexer.ts
while (src) {
const srcLength = src.length; // Guard variable added
// Tokenizer execution logic...
if (srcLength === src.length) { // Validation check
const infiniteLoopError = new Error('infinite loop');
throw infiniteLoopError;
}
}This structural fix is comprehensive because it addresses the bug class rather than simply adding the Vertical Tab to the whitespace regex. By enforcing strict progress validation, the parser defends against any future parsing edge cases that might result in unconsumed input. The maintainers also updated trimTrailingBlankLines in src/helpers.ts to use consistent regex validation across environments.
Exploitation requires the attacker to submit a precise three-byte payload to the target application. The exploit sequence consists of a horizontal tab (\x09), a Vertical Tab (\x0b), and a newline (\x0a). This payload is small enough to bypass most length-based input validation controls.
The attack methodology involves identifying an endpoint that routes user input to the marked library. The attacker then issues an HTTP POST request or WebSocket message containing the payload. No authentication or elevated privileges are required to deliver the payload to exposed endpoints.
Upon processing the payload, the target server's CPU utilization spikes to 100% on the single thread running the event loop. System memory consumption rises sharply as the parser allocates continuous heap space. Depending on the container memory limits or physical server specifications, the process crashes with ERR_WORKER_OUT_OF_MEMORY within seconds.
The primary impact of this vulnerability is total Denial of Service (DoS) for the affected Node.js process. Because Node.js operates primarily on a single-threaded event loop, the infinite recursion blocks all concurrent operations. Legitimate requests queued on the event loop remain unfulfilled while the parser exhausts system resources.
In architectures lacking robust health checks and automatic restart policies, a single malicious request can permanently disable the service. In orchestrated environments like Kubernetes, the OOM crash will trigger container restarts. However, continuous exploitation will result in a crash-loop state, sustaining the availability impact.
The vulnerability is scored as a 7.5 High under CVSS v3.1 and an 8.7 High under CVSS v4.0. The high scores reflect the trivial network exploitability and the complete loss of availability. The exploit requires no user interaction and operates against default configurations.
The current EPSS percentile is relatively low at 20.26%. This metric indicates the initial probability of exploitation in the wild at the time of disclosure. Given the functional and trivial nature of the PoC, threat actors can easily incorporate this payload into automated scanning and exploitation frameworks targeting Markdown-enabled web applications.
The definitive remediation is upgrading the marked library to version 18.0.2 or later. The patch introduces fundamental structural safeguards that terminate the parsing process if infinite recursion is detected. Developers should verify the dependency tree to ensure transitive dependencies are also updated.
If immediate patching is not technically feasible, organizations must implement application-level input sanitization. Middleware components can intercept incoming requests and strip or replace Vertical Tab (\x0b) characters before they reach the parser. This prevents the specific payload sequence from triggering the logic error.
Network defenders can deploy Web Application Firewall (WAF) rules to detect and drop HTTP requests containing the hex sequence 09 0b 0a. This signature specifically matches the proof-of-concept payload and blocks exploitation attempts at the edge network layer.
As a defense-in-depth measure, Node.js applications should be configured with explicit heap limits using the --max-old-space-size flag. Additionally, utilizing process managers like PM2 or container orchestration policies ensures the application automatically recovers from unexpected crashes, limiting the duration of the denial of service.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
marked markedjs | 18.0.0 - 18.0.1 | 18.0.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-835, CWE-400 |
| Attack Vector | Network |
| CVSS v3.1 | 7.5 (High) |
| EPSS Score | 0.07% |
| Impact | Denial of Service (OOM) |
| Exploit Status | PoC Available |
Loop with Unreachable Exit Condition ('Infinite Loop')