Aug 3, 2026·7 min read·0 visits
A resource exhaustion vulnerability in the brace-expansion library permits unauthenticated remote attackers to trigger process termination via heap memory exhaustion or lock the Node.js event loop by supplying crafted nested brace structures.
CVE-2026-69152 is a high-severity Denial of Service (DoS) vulnerability in brace-expansion that allows remote, unauthenticated attackers to cause a process crash or infinite thread-blocking condition. The vulnerability stems from a complete mitigation bypass of the security checks implemented for CVE-2026-14257.
The brace-expansion library is a standard dependency in the Node.js ecosystem, commonly used to expand shell-style brace patterns like file{1..3}.txt into list arrays. This utility is critical for file path globbing, pattern matching, and script processing workflows. Because the parsing engine handles raw strings, it frequently encounters untrusted inputs from CLI utilities, configuration files, or HTTP query parameters, establishing an accessible remote attack surface.
This vulnerability is classified under CWE-400 (Uncontrolled Resource Consumption) and CWE-770 (Allocation of Resources Without Limits or Throttling). It serves as a direct mitigation bypass of the fixes introduced for CVE-2026-14257. While the previous patch successfully constrained the final merged accumulator string and execution result counts, it failed to bound intermediate calculations, leaving the parsing engine vulnerable to excessive memory allocation and CPU starvation.
Attackers can exploit this structural omission by supplying carefully structured string sequences that generate highly nested intermediate states. These states bypass downstream safety barriers, leading to either Out-of-Memory (OOM) termination of the Node.js process or lockup of the single-threaded runtime.
The core vulnerability lies in the structural separation of parsing phases within the library. The parser processes input configurations in isolated recursion steps, returning intermediary arrays before merging them into a final output array. The initial defensive checks implemented for CVE-2026-14257 only limited the final aggregated result count and characters inside the combine() function.
The first bypass vector targets comma-separated alternative structures such as {alt1,alt2,alt3,...}. During processing, the library recursively calls expand() for each nested branch, enforcing the static maxLength limit separately on each individual branch. The parser then aggregates the results into a single flat array using values.push.apply(). Because there was no running global accumulator check during this assembly, an attacker can cascade $N$ nested branches, each staying just below the threshold, resulting in a total size that scales to $N \times \text{maxLength}$, exceeding the available Node.js heap.
The second bypass vector occurs within the expandSequence() sequence generator when handling padded ranges such as {00000...0001..100000}. This component was bound only by the maximum result count, ignoring string length boundaries. Although V8 uses efficient cons-strings internally to minimize memory footprint during generation, formatting each padded range requires quadratic time complexity relative to the width and size of the range, resulting in a thread-blocking lockup.
To understand the mechanical differences, we can contrast the vulnerable logic with the fixed implementation. In unpatched versions, the sequence generator lacked tracking of intermediate lengths and directly processed large spans. The patch integrates maxLength checks inside the generation loop to break early if size thresholds are exceeded.
// Sequence Generation Fix
function expandSequence(
body: string,
isAlphaSequence: boolean,
max: number,
+ maxLength: number, // Track current character limit constraints
): string[] {
...
const pad = n.some(isPadded)
+ let length = 0
for (let i = x; test(i, y) && N.length < max; i += incr) {
let c
...
+ // Validate if adding next element exceeds limit
+ if (length + c.length > maxLength) break
N.push(c)
+ length += c.length
}
return N
}Similarly, in the comma alternative processor expand_, the engine previously pushed items without validating running bounds. The patched version implements a running budget check valuesLength and executes an early loop break when the limit is breached, preventing excessive heap allocation.
// Alternative Expansion Logic Fix
values = []
- for (let j = 0; j < n.length; j++) {
- values.push.apply(values, expand_(n[j] as string, max, maxLength, false))
+ let valuesLength = 0
+ outer: for (let j = 0; j < n.length; j++) {
+ const expanded = expand_(n[j] as string, max, maxLength, false)
+ for (let k = 0; k < expanded.length; k++) {
+ const v = expanded[k] as string
+ if (dropsEmpties && !v) continue
+ // Enforce running budget validation
+ if (values.length >= max || valuesLength + v.length > maxLength) {
+ break outer
+ }
+ values.push(v)
+ valuesLength += v.length
+ }
}Exploitation of CVE-2026-69152 requires no privileges or complex environment variables, as the parser operates entirely on standard string inputs. In applications where user input is directly expanded—such as router parameters, search fields, or directory parsers—an attacker can pass malicious payloads directly.
The first attack pattern targets the comma array heap exhaustion. By chaining multiple nested sequences, the engine is forced to allocate extensive intermediate arrays, causing a process crash due to uncatchable out-of-memory errors.
// Payload A: Memory Exhaustion Proof-of-Concept
const expand = require('brace-expansion');
const alt = '{1..5}';
const payload = '{' + Array(1000).fill(alt).join(',') + '}';
// Triggers heap out-of-memory crash
expand(payload, { maxLength: 50 }); The second pattern targets the sequence pad generator. By specifying extremely wide leading zero paddings, the application CPU is saturated attempting to compute and pad strings, blocking the execution thread indefinitely.
// Payload B: CPU Thread Blocking Proof-of-Concept
const expand = require('brace-expansion');
const payload = '{' + '0'.repeat(400000) + '1..100000}';
// Locks the Node.js event loop
expand(payload);The patches implemented in versions 1.1.18, 2.1.4, 3.0.6, and 5.0.9 effectively mitigate the primary out-of-memory and CPU loop-locking conditions. By enforcing limits on intermediate string sizes and sequences, the library protects runtime stability. However, security architects must consider the implications of the remediation design.
The engine now uses silent truncation when a boundary is hit, halting expansion processing rather than raising an explicit error exception. In downstream applications that rely on full expansion for input validation or policy rules—such as access control list parsing or path filters—silent truncation could lead to incomplete validation checks, introducing logical bypasses.
Additionally, in environments where max defaults to Infinity and empty strings are generated (such as {,}{,}{,} chains where dropsEmpties resolves to false), the tracking variable valuesLength remains unchanged because empty strings have a length of zero. While these arrays contain lightweight entries, extremely deep configurations can still lead to extensive array allocations, representing a vector for minor heap bloat.
The most effective path to remediation is upgrading to the patched package versions across all active projects. For applications unable to update dependencies immediately, input length limits should be implemented as a temporary defense. Limiting external inputs to a maximum size (such as 256 characters) prevents the construction of nested structures.
Applications should avoid executing potentially intensive utility operations on the primary thread. Running parse operations inside worker threads or sandboxed processes prevents any potential thread blocking from affecting the main application logic.
Intrusion detection rules should scan incoming query parameters and payloads for dense nested braces or highly padded sequence patterns. Signatures matching recursive sequences can help flag and drop malicious inputs before they reach the execution engine.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
brace-expansion Julian Gruber | < 1.1.18 | 1.1.18 |
brace-expansion Julian Gruber | >= 2.0.0, < 2.1.4 | 2.1.4 |
brace-expansion Julian Gruber | >= 3.0.0, < 3.0.6 | 3.0.6 |
brace-expansion Julian Gruber | >= 4.0.0, < 5.0.9 | 5.0.9 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400, CWE-770 |
| Attack Vector | Network |
| CVSS Score | 7.5 |
| EPSS Score | Not available |
| Impact | Denial of Service (Availability) |
| Exploit Status | Proof of Concept (PoC) available |
| KEV Status | Not listed |
The software does not properly control the allocation and maintenance of a limited resource, enabling an actor to influence the amount of resources consumed.
A directory traversal and arbitrary file read vulnerability exists in PostCSS due to an incomplete fix of CVE-2026-45623. When parsing a CSS file containing a sourceMappingURL comment with the 'from' parameter unset, path traversal and absolute path validations are bypassed, enabling attackers to read arbitrary local .map files.
An in-depth technical analysis of CVE-2026-68945, a high-severity security vulnerability in Angular's `@angular/common/http` package. The flaw stems from an ambiguity in how query parameters are serialized to generate cache keys during Server-Side Rendering (SSR) within the `HttpTransferCache` component. By failing to encode delimiters and implicitly coercing arrays to comma-joined strings, the serialization mechanism yields identical cache keys for distinct requests, facilitating State Poisoning and Cross-Request Response Reuse.
A critical heap out-of-bounds (OOB) write vulnerability exists in the Linux kernel's IPv6 RPL (Routing Protocol for Low-Power and Lossy Networks) Segment Routing Header (SRH) processing logic. The vulnerability is located within net/ipv6/exthdrs.c, specifically in the ipv6_rpl_srh_rcv function. Under specific circumstances, when a packet containing a compressed RPL Source Routing Header is processed, segment swapping can reduce the common-prefix length, causing the recompressed header to grow. Because the kernel fails to validate available headroom on intermediate segments, a buffer underflow occurs during skb_push. This leads to an integer wrap in the MAC header offset pointer during MAC header rebuilding, causing a 14-byte out-of-bounds memory write roughly 64 KiB past the socket buffer.
CVE-2026-58263 is a high-severity Mutation Cross-Site Scripting (mXSS) vulnerability affecting Jodit Editor prior to version 4.12.28. The flaw exists in Jodit's built-in clean-html sanitizer plugin, which fails to securely parse and sanitize nested elements containing foreign namespaces like MathML and SVG. Attackers can bypass sanitization by smuggling malicious payload elements inside rawtext container tags like style inside a MathML node, leading to DOM mutation and unauthenticated arbitrary script execution in the context of the user's browser session.
Jodit Editor versions prior to 4.13.6 are vulnerable to client-side Cross-Site Scripting (XSS). The clean-html plugin's sanitization routine performs case-sensitive lookups against uppercase-only element blacklists. When processing XML-based foreign namespaces such as SVG or MathML, DOM engines preserve the lowercase format of tags. Because Jodit's denyTags check fails to normalize tag casing, malicious script blocks nested inside foreign namespace elements completely bypass validation and serialize directly into the editor output.
A critical code injection vulnerability exists in Savon, a widely used SOAP client library for Ruby, prior to version 2.17.2. The vulnerability resides within the Savon::Model.all_operations module, where operation names fetched from a target Web Services Description Language (WSDL) document are dynamically evaluated via module_eval without sanitization. An attacker capable of manipulating the target WSDL document (e.g., through Man-in-the-Middle attacks, DNS hijacking, or Server-Side Request Forgery) can execute arbitrary Ruby code in the context of the parent application process.