Aug 8, 2026·6 min read·29 visits
SvelteKit versions before 2.70.2 are vulnerable to a CPU-exhausting ReDoS via malformed Accept headers due to an unanchored regular expression in its content negotiation parser.
A Regular Expression Denial of Service (ReDoS) vulnerability exists in SvelteKit's content negotiation header parser prior to version 2.70.2. An unauthenticated remote attacker can exploit this vulnerability by sending a crafted Accept header with highly repetitive malformed values. This triggers catastrophic backtracking on the single-threaded Node.js/Bun event loop, leading to CPU exhaustion and full denial of service.
SvelteKit utilizes a content negotiation system to determine how to format and serve responses to clients. This mechanism, residing in packages/kit/src/utils/http.js, inspects incoming HTTP request headers—specifically the Accept header—to identify the appropriate MIME types requested by the client.
Because content negotiation occurs globally early in the middleware request lifecycle, the parsing path is exposed to all incoming network requests. This introduces an unauthenticated attack surface that does not require any session establishment, specific API privileges, or application-specific configurations.
The parsing logic relies on a regular expression designed to break down comma-separated MIME types and extract quality values (such as q=0.9). However, due to an unanchored configuration within this pattern (CWE-1333), the parser is susceptible to a catastrophic backtracking loop when presented with a specially crafted string. An attacker can exploit this behavior to force high CPU utilization, exhausting server-side compute resources.
The root cause of this vulnerability lies in the unanchored nature of SvelteKit's MIME-type parsing regular expression:
/([^/ \\t]+)\\/([^; \\t]+)[ \\t]*(?:;[ \\t]*q=([0-9.]+))?/When evaluating a regular expression, engines typically attempt to find a match starting at the first character of the string. If a match attempt fails, and the regular expression does not contain a start anchor (such as ^), the engine advances the starting pointer to the next character in the string and restarts the entire matching routine.
Consider an input string of length $N$ consisting entirely of the character 'a' without any forward slash / (e.g., "aaaa...aaa"). The engine begins matching at index 0, where the greedy group ([^/ \\t]+) matches the entire sequence of $N$ characters. The engine then attempts to match the literal slash \\/ character, which is missing from the input. This mismatch triggers back-tracking, forcing the engine to test smaller subsets of the greedy group.
Once all backtracking paths at index 0 fail, the unanchored engine shifts its starting window to index 1 and repeats the process. It continues this behavior for every index up to $N$. This results in a quadratic execution complexity of $O(N^2)$, executing roughly $\frac{N \times (N+1)}{2}$ steps. In a single-threaded execution model like Node.js or Bun, this computationally intensive loop completely blocks the main event loop.
The vulnerable logic is found within the negotiate function inside packages/kit/src/utils/http.js. The function splits the Accept header on commas and processes each segment:
// Vulnerable Code Path
export function negotiate(accept, types) {
const parts = [];
accept.split(',').forEach((str, i) => {
// Unanchored regex allows the engine to retry matching at every character offset
const match = /([^/ \\t]+)\\/([^; \\t]+)[ \\t]*(?:;[ \\t]*q=([0-9.]+))?/.exec(str);
if (match) {
// processing matches...
}
});
}The fix, introduced in commit 82712fc02c24b1dcf5b25d7a52129cd8455f04f5, prepends the start-of-line anchor ^[ \\t]* to lock the evaluation to the very beginning of each segment:
// Patched Code Path
export function negotiate(accept, types) {
const parts = [];
accept.split(',').forEach((str, i) => {
// Prepending the ^ anchor limits attempts strictly to the beginning of the string
const match = /^[ \\t]*([^/ \\t]+)\\/([^; \\t]+)[ \\t]*(?:;[ \\t]*q=([0-9.]+))?/.exec(str);
if (match) {
// processing matches...
}
});
}By forcing the regular expression to match only from the start of the string, the engine is prevented from shifting its evaluation window. If the match fails at index 0, the evaluation is immediately aborted. This restricts the execution complexity to a safe, linear $O(N)$ runtime.
Exploitation of this vulnerability is straightforward and requires only a single, malformed HTTP request. An attacker targets any SvelteKit endpoint with a custom Accept header containing a highly repetitive pattern of alphanumeric characters containing no slash.
An example of a conceptual payload sent via HTTP:
GET / HTTP/1.1
Host: vulnerable-app.internal
Accept: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Connection: closeBecause many standard web servers and reverse proxies enforce an 8 KB limit on request headers, the size of a single header segment is physically constrained. However, even an 8,000-character payload forces millions of evaluations inside the regular expression engine. Multiple concurrent requests containing this payload will quickly saturate all available CPU threads allocated to the Node.js application process.
The impact of this vulnerability is a complete loss of service availability. While confidential data exposure and unauthorized write actions are not possible (resulting in a CVSS vector of C:N/I:N/A:L or A:H depending on deployment topology), the blocking of the single-threaded Node.js or Bun event loop ensures that no other network requests can be processed.
In containerized or auto-scaling environments (such as AWS ECS, Kubernetes, or serverless platforms), the CPU exhaustion will trigger horizontal scaling, potentially resulting in inflated operational costs. In single-instance node architectures, this attack will permanently freeze the web server until the process is manually restarted or killed by a health check timeout.
The recommended remediation is upgrading @sveltejs/kit to version 2.70.2 or later. This replaces the vulnerable regular expression engine configuration with the anchored version.
If immediate software upgrade is not possible, implement the following mitigations:
Accept headers longer than 1024 bytes.Accept header contains long contiguous sequences of letters without a / character.SvelteKit developers integrated the following regression test inside packages/kit/src/utils/http.spec.js to ensure backtracking issues do not reappear:
test('ignores an accept segment with no slash without catastrophic backtracking', () => {
assert.equal(negotiate('a'.repeat(200_000), ['text/html']), undefined);
}, 100);This test suite fails if the execution of negotiate on a 200,000-character string takes longer than the strict 100ms timeout threshold.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L| Product | Affected Versions | Fixed Version |
|---|---|---|
@sveltejs/kit Svelte | < 2.70.2 | 2.70.2 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-1333 (Inefficient Regular Expression Complexity) |
| Attack Vector | Network (AV:N) |
| CVSS | 5.3 (Medium) |
| EPSS | N/A |
| Impact | Denial of Service (DoS) |
| Exploit Status | PoC Available |
| KEV Status | Not Listed |
The software uses a regular expression that can take a very long time to evaluate on certain inputs, leading to a Denial of Service.
An uncontrolled resource consumption vulnerability exists in the Docling document conversion library. Maliciously structured HTML, JATS, ODS, or BoxNote inputs containing table cells with excessively large 'rowspan' or 'colspan' attribute values trigger algorithmic complexity conditions. This allows unauthenticated remote attackers to initiate resource exhaustion states, crashing or hanging the target document processing pipeline while bypassing configured timeouts.
A Local File Inclusion (LFI) and Arbitrary File Disclosure vulnerability exists in Docling and Docling Slim versions >= 2.16.0 up to 2.131.0. When parsing serialized DoclingDocument structures using the JSON input format, the backend fails to restrict image URI schemes, allowing remote attackers to retrieve local files and verify path existence on the host system during embedded document export.
Docling, a tool for parsing and processing diverse document formats, is vulnerable to arbitrary file read, arbitrary file write, and potential remote code execution (RCE) in versions 2.94.0 through 2.131.0. The vulnerability occurs when applications configure Docling to use the Tectonic engine for rendering TikZ diagrams into images. Because the compilation did not restrict hazardous TeX primitives or sandbox the environment, an attacker can supply crafted documents containing malicious TikZ definitions to access or modify local files and execute arbitrary commands under the privileges of the processing application.
An SSRF guard bypass vulnerability in the Docling document conversion engine allows unauthenticated attackers to bypass internal IP access controls. The vulnerability exists due to a DNS rebinding Time-of-Check Time-of-Use (TOCTOU) condition, URL authority parsing inconsistencies, and unvalidated network requests triggered during headless browser page rendering.
A technical analysis of CVE-2026-105742 (GHSA-p3fw-7699-7926), a sensitive information disclosure vulnerability in the Docling document processing library. Vulnerable versions of Docling indiscriminately forward custom HTTP headers, such as authentication tokens, to arbitrary third-party origins and during cross-origin redirects while fetching remote image assets from untrusted HTML and EPUB documents.
CVE-2026-106121 is a Denial of Service (DoS) vulnerability in the RabbitMQ Java Client library (amqp-client) affecting versions prior to 5.37.0. The vulnerability resides in the legacy, custom JSON-RPC parsing class com.rabbitmq.tools.json.JSONReader. When parsing malformed or truncated payloads ending within a quoted string or single-line comment, the parser's scanner enters an infinite loop. This occurs because the loop lacks an exit condition for the end-of-input sentinel character returned by the iterator, leading to either CPU exhaustion or a JVM crash from an OutOfMemoryError.