CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-119202

CVE-2026-119202: Regular Expression Denial of Service in @hapi/content Header Parsing

Alon Barad
Alon Barad
Software Engineer

Oct 31, 2026·9 min read·3 visits

Executive Summary (TL;DR)

@hapi/content versions 3.0.6 through 6.0.2 are vulnerable to quadratic Regular Expression Denial of Service (ReDoS) in Content.disposition() when parsing Content-Disposition headers containing long tokens without an equals sign. Upgrading to @hapi/content version 6.0.3 resolves the issue.

A regular expression denial of service (ReDoS) vulnerability exists in @hapi/content from version 3.0.6 prior to 6.0.3. The Content.disposition() function utilizes an unanchored parameter-name regular expression inside a global replacement scan. When processing a Content-Disposition header parameter containing a long token lacking an equals sign, the JavaScript regular expression engine undergoes quadratic O(N^2) backtracking. Because @hapi/content is invoked by @hapi/pez during multipart/form-data request parsing, unauthenticated remote attackers can send a crafted multipart request to any Hapi route with multipart payload parsing enabled, starving the single-threaded Node.js event loop.

Vulnerability Overview

@hapi/content is the core HTTP Content-* header parsing utility library used across the Node.js and Hapi framework ecosystem. It provides functions to parse and validate Content-Type and Content-Disposition headers according to HTTP specifications, including RFC 6266 and RFC 5987. Within the Hapi framework architecture, @hapi/content is an upstream dependency of @hapi/pez, the multipart stream parser responsible for processing multipart/form-data HTTP request payloads.

A vulnerability classified under CWE-1333 (Inefficient Regular Expression Complexity) exists in @hapi/content starting in version 3.0.6 and affecting all releases prior to version 6.0.3. Specifically, the Content.disposition() function executes a global regular expression scan (internals.contentDispositionParamRegex) to extract key-value parameters from Content-Disposition headers. Due to an unanchored initial character class matching parameter names, malformed parameter tokens that omit the mandatory = delimiter force the V8 regular expression engine into quadratic $O(N^2)$ time complexity.

The primary attack surface includes any Hapi server route configured with payload.multipart enabled, as well as standalone Node.js applications that pass untrusted HTTP headers directly to Content.disposition(). In Hapi applications, @hapi/pez invokes Content.disposition() on each part's headers inside the multipart stream before route-level input validation or handler logic executes. Consequently, an unauthenticated remote attacker can trigger synchronous CPU exhaustion on the main Node.js execution thread via a single HTTP request, blocking the event loop and causing an application-wide denial of service.

Root Cause Analysis

The root cause of CVE-2026-119202 is the interaction between an unanchored negated character class at the beginning of internals.contentDispositionParamRegex and the global match flag (/g) used during String.prototype.replace(). When Content.disposition(header) parses a Content-Disposition header, it first verifies the form-data prefix using internals.contentDispositionRegex and isolates the remaining parameter string. It then iterates over the parameter string by passing internals.contentDispositionParamRegex to parameters.replace().

In vulnerable versions, internals.contentDispositionParamRegex begins with the capture group ([^\=\*\s]+), which greedily matches one or more characters that are not an equals sign (=), an asterisk (*), or whitespace. Immediately following this group is the optional extended parameter indicator (\*)? and the required delimiter pattern \s*\=\s*. For a valid parameter such as name="field", the first group consumes name, matches the =, and consumes the value in linear time.

When the parameter string contains a contiguous sequence of $N$ characters lacking an equals sign, asterisk, or whitespace (for example, form-data; name="f"; aaaaa...), the regular expression engine starts at index $i = 0$ of the malformed token and greedily consumes all $N$ characters into the ([^\=\*\s]+) group. The engine then attempts to match \s*\=\s* at the end of the string, which fails because no = is present. Because the pattern is unanchored and uses the /g flag, the regular expression engine's failure recovery mechanism advances the starting search index by a single character to $i = 1$ and re-evaluates the entire pattern.

At index $i = 1$, ([^\=\*\s]+) consumes the remaining $N - 1$ characters, fails again on the missing =, and advances to $i = 2$. This cycle repeats for every character in the $N$-length token. The total number of character comparisons performed by the regular expression engine equals $\sum_{i=1}^{N} i = \frac{N(N+1)}{2}$, yielding $O(N^2)$ quadratic complexity. For a token of $64,000$ characters, the engine executes approximately $2.048 \times 10^9$ character evaluations synchronously on the main V8 thread.

Code Analysis

The vulnerability is located in lib/index.js within the hapijs/content repository. Prior to version 6.0.3, internals.contentDispositionParamRegex only defined matching branches for well-formed key-value pairs where an = character was present. If a parameter segment lacked an =, the regex engine had no way to consume and discard the segment in a single pass.

// Vulnerable code in lib/index.js (prior to v6.0.3)
internals.contentDispositionRegex = /^\s*form-data\s*(?:;\s*(\S.*))?$/i;
 
//                                        1: name     2: *            3: ext-value                      4: quoted  5: token
internals.contentDispositionParamRegex = /([^\=\*\s]+)(\*)?\s*\=\s*(?:([^;'"\s]+\'[\w-]*\'[^;\s]+)|(?:"([^"]*)")|([^;\s]*))/g;
 
exports.disposition = function (header) {
    // ... header validation and prefix extraction ...
    const extKeys = new Set();
    parameters.replace(internals.contentDispositionParamRegex, ($0, $1, $2, $3, $4, $5) => {
 
        if ($1 === '__proto__') {
            throw Boom.badRequest('Invalid content-disposition header format includes invalid parameters');
        }
        // ... parameter extraction logic ...
    });
};

In commit 0993851dc7234976a3fce3a7c31662b213c940fd, the maintainer modified internals.contentDispositionParamRegex by appending an uncaptured alternation branch |[^\=\*\s]+ at the end of the expression, and added an early return check in the .replace() callback.

// Patched code in lib/index.js (v6.0.3)
// The trailing alternative consumes a name that isn't followed by "=", otherwise the global scan retries from every
// character of it and backtracks quadratically, any later start in the same run would fail the same way anyway.
 
//                                        1: name     2: *            3: ext-value                      4: quoted  5: token     skipped
internals.contentDispositionParamRegex = /([^\=\*\s]+)(\*)?\s*\=\s*(?:([^;'"\s]+\'[\w-]*\'[^;\s]+)|(?:"([^"]*)")|([^;\s]*))|[^\=\*\s]+/g;
 
exports.disposition = function (header) {
    // ...
    const extKeys = new Set();
    parameters.replace(internals.contentDispositionParamRegex, ($0, $1, $2, $3, $4, $5) => {
 
        // If $1 is undefined, the trailing fallback branch matched a token without '='.
        // Ignore the token and return immediately.
        if ($1 === undefined) {
            return;
        }
 
        if ($1 === '__proto__') {
            throw Boom.badRequest('Invalid content-disposition header format includes invalid parameters');
        }
        // ...
    });
};

> [!NOTE] > Fix Completeness Assessment: The patch completely eliminates the quadratic backtracking behavior on malformed tokens. When the primary branch fails at index $i=0$ due to a missing =, the regex engine immediately evaluates the second alternation branch (|[^\=\*\s]+) at index $i=0$. This branch matches the entire contiguous run of non-delimiter characters in a single pass, advancing the regex lastIndex pointer past the end of the token. Because no capture groups exist in the fallback branch, $1 evaluates to undefined inside the callback, causing it to return immediately. This restores strict $O(N)$ linear time complexity without altering the functional return value of Content.disposition().

Exploitation

Exploiting CVE-2026-119202 requires no authentication or session state if the target application exposes an HTTP endpoint that parses Content-Disposition headers or accepts multipart/form-data payloads via Hapi's built-in multipart handling. In a network attack scenario against a Hapi server, the attacker sends an HTTP POST or PUT request with a Content-Type: multipart/form-data; boundary=... header. Inside the multipart body, the part header is crafted to include a Content-Disposition line containing a large sequence of characters without an equals sign.

Because @hapi/pez parses multipart headers while streaming the request body, the payload size is not limited by standard HTTP request header size limits enforced by Node.js (--max-http-header-size, typically 16 KB), as multipart part headers reside inside the HTTP request body. Instead, the size of the crafted Content-Disposition header is bounded only by the route's payload.maxBytes configuration (which defaults to 1 MB in @hapi/hapi) or any internal buffer limits in @hapi/pez.

The following standalone proof-of-concept demonstrates the local reproduction of the vulnerability using @hapi/content, matching the regression test cases introduced in commit 0993851dc7234976a3fce3a7c31662b213c940fd:

const Content = require('@hapi/content');
 
// Construct a Content-Disposition header with a 64,000-byte token lacking '='
const payload = 'a'.repeat(64000);
const header = `form-data; name="f"; ${payload}`;
 
const start = Date.now();
const result = Content.disposition(header);
const duration = Date.now() - start;
 
console.log('Parsed result:', result);
console.log(`Execution time: ${duration} ms`);

As demonstrated in the official test suite in test/index.js, the vulnerable code path is triggered whether the malformed token appears at the end of the header (form-data; name="f"; aaaaa...) or precedes valid parameters (form-data; aaaaa...; name="f"; filename=file.jpg). On vulnerable versions (< 6.0.3), a 64,000-character token blocks the Node.js event loop for multiple seconds per invocation, pinning a CPU core at 100% utilization. On patched versions (>= 6.0.3), both payloads execute in under 10 milliseconds.

Impact Assessment

The primary impact of CVE-2026-119202 is high availability loss (Denial of Service), reflected in its CVSS v3.1 score of 7.5 (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H). The attack vector is Network (AV:N), Attack Complexity is Low (AC:L), Privileges Required is None (PR:N), and User Interaction is None (UI:N). Confidentiality (C:N) and Integrity (I:N) are unaffected, as the flaw does not permit memory corruption, out-of-bounds reads, or unauthorized state modification.

In a Node.js runtime environment, JavaScript code and regular expression evaluation execute synchronously on a single main event loop thread. When Content.disposition() enters the quadratic backtracking loop, the V8 engine cannot yield execution to process other pending I/O events, timers, or incoming network connections. Every other concurrent user request handled by the same Node.js worker process is stalled until the regular expression evaluation finishes.

Furthermore, because multipart header parsing in @hapi/pez occurs during the payload parsing phase of the Hapi request lifecycle, it executes prior to route-level validation (options.validate.payload) and route handler execution. If a route allows multipart payloads without requiring prior authentication, an attacker can continuously transmit small, low-bandwidth multipart requests to keep the event loop permanently saturated, causing health check failures and upstream load balancer timeouts.

Threat intelligence metrics currently indicate an EPSS score of 0.00411 (35.40th percentile), and the vulnerability is not listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. While no mass weaponized exploitation has been recorded in public exploit databases, the triviality of constructing the payload makes any internet-facing Hapi multipart endpoint susceptible to service disruption.

Remediation

To remediate CVE-2026-119202, upgrade @hapi/content to version 6.0.3 or later. Applications that depend on @hapi/content directly can update the package via standard package managers:

npm install @hapi/content@^6.0.3

In most Hapi deployments, @hapi/content is installed as a transitive dependency of @hapi/pez or @hapi/hapi. Operators should inspect their dependency tree using npm ls @hapi/content to identify all installed versions. If an older version (>= 3.0.6, < 6.0.3) is locked by a parent package, enforce version resolution in package.json using the overrides field (for npm) or resolutions field (for Yarn/pnpm):

{
  "overrides": {
    "@hapi/content": "^6.0.3"
  }
}

If immediate package patching is not operationally feasible, several defense-in-depth mitigations can reduce exposure:

  1. Disable Unnecessary Multipart Parsing: Audit Hapi route configurations and disable payload.multipart on routes that do not explicitly require multipart file or form uploads.
  2. Enforce Authentication Pre-Parsing: Where possible, require authentication before allowing large or multipart request bodies to be processed, or restrict access to multipart endpoints at the API gateway level.
  3. WAF and Reverse Proxy Filtering: Configure upstream reverse proxies (such as NGINX, Envoy, or cloud WAFs) to inspect Content-Disposition headers and multipart bodies, rejecting requests containing contiguous non-whitespace parameter tokens without an = sign exceeding 256 bytes.

Official Patches

hapijsGit commit resolving the quadratic regular expression backtracking in Content.disposition().
hapijs@hapi/content v6.0.3 release tag.
GitHubOfficial GitHub Security Advisory GHSA-8494-f6mr-cjpv.

Fix Analysis (1)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.41%
Top 65% most exploited

Affected Systems

@hapi/content@hapi/pez@hapi/hapi

Affected Versions Detail

Product
Affected Versions
Fixed Version
@hapi/content
hapijs
>= 3.0.6, < 6.0.36.0.3
AttributeDetail
Vulnerability IDCVE-2026-119202 / GHSA-8494-f6mr-cjpv
CWE ClassificationCWE-1333 (Inefficient Regular Expression Complexity)
CVSS v3.1 Score7.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
EPSS Score0.41% (35.40th Percentile)
Affected Component@hapi/content (>= 3.0.6, < 6.0.3) - Content.disposition()
Patched Version@hapi/content 6.0.3
ImpactUnauthenticated Node.js Event Loop Starvation (DoS)
CISA KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
T1499.003Endpoint Denial of Service: Application Exhaustion Flood
Impact
CWE-1333
Inefficient Regular Expression Complexity

The product uses a regular expression that can be made to run in polynomial or exponential time relative to the size of the input, leading to excessive resource consumption (CPU starvation) and Denial of Service (ReDoS).

Known Exploits & Detection

GitHubOfficial patch commit containing unit test cases reproducing the 64,000-character ReDoS payload.

Vulnerability Timeline

Patch commit 0993851dc7234976a3fce3a7c31662b213c940fd authored and committed to hapijs/content.
2026-10-21
GitHub Security Advisory GHSA-8494-f6mr-cjpv and CVE-2026-119202 published.
2026-10-29
CVE-2026-119202 published to the National Vulnerability Database (NVD).
2026-10-29
NVD analysis completed and CVSS v3.1 vector assigned.
2026-10-30

References & Sources

  • [1]GitHub Security Advisory GHSA-8494-f6mr-cjpv
  • [2]Patch Commit 0993851dc7234976a3fce3a7c31662b213c940fd in hapijs/content
  • [3]@hapi/content Release v6.0.3
  • [4]NVD - CVE-2026-119202
  • [5]CVE.org Record - CVE-2026-119202
  • [6]CVEListV5 Record - CVE-2026-119202.json

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•28 minutes ago•CVE-2026-118764
6.9

CVE-2026-118764: Asymmetric Resource Consumption and Denial of Service in minimatch Pattern Preprocessing

CVE-2026-118764 (also tracked as GHSA-g3hv-75wg-m249) is an asymmetric resource consumption vulnerability (CWE-405) in the npm package minimatch prior to version 11.0.1. When pattern compilation is invoked with an optimizationLevel of 2 or higher, the internal preprocessing functions firstPhasePreProcess() and secondPhasePreProcess() in src/index.ts perform unbounded pattern splitting and quadratic pairwise deduplication. An attacker supplying a crafted glob string containing repeated **/.. segments can induce a combinatorial explosion of pattern permutations followed by an O(M^2) comparison routine, blocking the Node.js event loop and exhausting process memory.

Amit Schendel
Amit Schendel
2 views•9 min read
•about 2 hours ago•CVE-2026-118772
7.5

CVE-2026-118772: Regular Expression Denial of Service in Joi Email Validation

A Regular Expression Denial of Service (ReDoS) vulnerability exists in the joi schema description and data validation library for JavaScript. When validating multiple email addresses using the Joi.string().email({ multiple: true }) configuration, the library compiles a separator regular expression with an unanchored greedy leading whitespace quantifier. Supplying an input string containing a long sequence of whitespace characters without the expected delimiter triggers quadratic time complexity during String.prototype.split execution, blocking the single-threaded Node.js event loop.

Alon Barad
Alon Barad
4 views•11 min read
•about 3 hours ago•CVE-2026-119205
7.1

CVE-2026-119205: Denial of Service via Infinite Loop in pypdf DictionaryObject Cloning

CVE-2026-119205 (GHSA-mfr5-77xh-9j7h) is a Denial of Service (DoS) vulnerability in pypdf prior to version 6.21.4. The flaw occurs during the cloning or duplication of nested PDF dictionary structures. Because the cycle-detection algorithm within DictionaryObject._clone() tracked generated destination object references rather than the original source indirect references, cyclic reference graphs in source PDFs evaded detection, resulting in an infinite loop and CPU exhaustion.

Alon Barad
Alon Barad
4 views•9 min read
•about 4 hours ago•CVE-2026-119204
7.1

CVE-2026-119204: Uncontrolled Resource Consumption in pypdf Page Tree Flattening

CVE-2026-119204 (also tracked as GHSA-cggf-277g-3q54) is a Denial of Service (DoS) vulnerability in pypdf prior to version 6.21.4. The vulnerability stems from uncontrolled resource consumption (CWE-400) during the flattening of a PDF document's page tree. By supplying a compact PDF containing a hierarchical amplification structure of shared `/Pages` and `/Page` nodes with dense dictionary entries or inherited resources, an unauthenticated attacker can cause pypdf to copy millions of dictionary entries into individual `PageObject` instances without enforcing a document-wide entry budget. This triggers severe heap memory exhaustion and process termination via Out-Of-Memory (OOM) kills.

Alon Barad
Alon Barad
4 views•11 min read
•about 5 hours ago•CVE-2026-119203
7.1

CVE-2026-119203: Infinite Loop in pypdf Standard Cross-Reference Table Parser

CVE-2026-119203 is a denial-of-service vulnerability affecting the pypdf library in versions prior to 6.21.4. The flaw occurs within the standard cross-reference (xref) table parsing routine when processing truncated or malformed PDF streams that terminate before a valid trailer dictionary is encountered. Because the parser attempts to rewind the stream pointer by a fixed offset whenever the trailer token is absent without verifying forward progress, hitting the end-of-file (EOF) or non-advancing tokens causes the parser to re-read the same byte offset indefinitely. An unauthenticated attacker can exploit this flaw by supplying a crafted PDF document to an application using pypdf, resulting in continuous CPU consumption and thread exhaustion.

Amit Schendel
Amit Schendel
4 views•9 min read
•about 6 hours ago•CVE-2026-118759
7.5

CVE-2026-118759: Cross-Tenant Pod Log Exposure via Authorization Bypass in Kubeflow Pipelines

Prior to version 2.18.0, the Kubeflow Pipelines API server contains a missing authorization and confused deputy vulnerability in its run log streaming endpoint. The HTTP handler for `GET /apis/v1alpha1/runs/{run_id}/nodes/{node_id}/log` fails to propagate incoming request headers to gRPC metadata and omits caller authorization checks against the requested run. Furthermore, the backend accepts the caller-supplied `node_id` parameter directly as a Kubernetes pod name without verifying that the pod belongs to the specified pipeline run. An attacker with network access to the API server who knows a valid run identifier can read live or archived execution logs from any pod containing a `main` container within the run's Kubernetes namespace.

Alon Barad
Alon Barad
4 views•10 min read