Sep 16, 2026·6 min read·35 visits
An unanchored substring matching flaw in http4s's CookieJar client middleware allows session cookies to be leaked to attacker-controlled origins during outbound HTTP requests.
A medium-severity cross-origin cookie leakage vulnerability exists in the CookieJar client middleware of the http4s library. Due to unanchored substring searches used to determine whether a cookie applies to an outbound request, sensitive cookies (such as session IDs and credentials) can be inadvertently sent to unauthorized domains or paths.
The vulnerability lies within the client-side CookieJar middleware of the http4s library. http4s is a functional, streaming HTTP interface for Scala applications. When the CookieJar middleware is enabled, it acts as an automated repository for maintaining HTTP cookies across sequential requests.
The vulnerability is categorized as a failure to validate authority boundaries during cookie retrieval and propagation. In standard HTTP client implementations, cookie scoping must strictly adhere to the domain-matching and path-matching criteria defined in RFC 6265. This boundary ensures that sensitive authorization cookies are never transmitted to unauthorized origins.
Instead of implementing RFC 6265 compliant matching logic, the client middleware historically relied on unanchored substring comparisons. This mechanism causes the client to send sensitive cookies to unauthorized third-party domains or incorrect sub-paths under specific conditions. As a result, any application performing outbound requests to external, user-supplied, or redirected destinations is vulnerable to credential exposure.
The root cause of the cookie leakage is located in the cookieAppliesToRequest method inside the companion object of the CookieJar class. This method validates whether a stored ResponseCookie should be appended to a new outbound Request based on three main properties: the host domain, the path, and the connection security.
To determine domain eligibility, the vulnerable code evaluates if the requested URI host authority contains the cookie's domain attribute as a substring. It performs this evaluation using the Scala .contains method. Because the check is completely unanchored, a cookie intended for example.com is deemed applicable to any destination host that has example.com as a substring, such as evilexample.com or example.com.attacker.net.
Similarly, the path validation logic compares the target path against the cookie's path attribute using another unanchored .contains check. If a cookie is restricted to /admin, the middleware will attach it to requests heading to /administrator or /public/admin-docs. This violates path boundary rules and permits cross-path session exposure.
The following diagram illustrates how the vulnerable validation logic permits unauthorized cross-origin transmission of cookies.
The code-level flaw is visible when comparing the vulnerable and patched implementations within CookieJar.scala. The vulnerable version evaluates both domain and path matching purely as raw string containment checks. This logic ignores structural boundaries such as dot delimiters in domains or slashes in paths.
// Vulnerable Implementation
private[middleware] def cookieAppliesToRequest[N[_]](
r: Request[N],
c: ResponseCookie,
): Boolean = {
val domainApplies = c.domain.exists(s =>
r.uri.host.forall { authority =>
authority.renderString.contains(s) // Fails on evilexample.com
}
)
val pathApplies = c.path.forall(s => r.uri.path.renderString.contains(s)) // Fails on /administrator
// ...
}To correct this vulnerability, the maintainers implemented helper methods called domainMatches and pathMatches which closely align with the rules of RFC 6265. These functions enforce exact matches, proper subdomain delegation, and path-segment boundaries.
// Patched Implementation
private def domainMatches(host: Uri.Host, cookieDomain: String): Boolean = {
val requestHost = host.value.toLowerCase(Locale.ROOT)
val domain = cookieDomain.toLowerCase(Locale.ROOT).stripPrefix(".")
domain.nonEmpty && {
host match {
case _: Uri.Ipv4Address | _: Uri.Ipv6Address =>
requestHost == domain
case _: Uri.RegName =>
requestHost == domain || requestHost.endsWith("." + domain)
}
}
}In the patched domain-matching logic, case folding is explicitly performed using Locale.ROOT to prevent internationalization bypasses. Additionally, IP addresses are restricted to exact equality checks, while standard hostnames are validated to ensure they are either an exact match or a valid subdomain ending with a dot delimiter. This eliminates substring matching on sibling domains.
An attacker can exploit this vulnerability if they can coerce the vulnerable Scala application into dispatching an outbound request to an attacker-controlled destination. Common vectors to achieve this include Server-Side Request Forgery (SSRF) vulnerabilities, user-defined webhooks, or open redirects. The attacker does not need prior authorization to exploit this flaw.
Consider an application that allows users to provide an external image URL for profile customization. If the application first communicates with https://example.com and obtains a session cookie, that cookie is stored in the CookieJar middleware. Subsequent requests initiated by the same client wrapper will reuse this state.
When the application attempts to fetch the attacker's image hosted at http://evilexample.com, the CookieJar matches "evilexample.com" with the stored "example.com" domain. The client then includes the Cookie header in the outbound HTTP request. The attacker's server captures the request headers, thereby compromising the session credentials of the application.
The impact of this vulnerability is the compromise of confidential credentials and session tokens managed by the http4s client. Depending on the architecture, this can lead to privilege escalation or unauthorized system access on behalf of the vulnerable application. If the cookie contains administrative session keys, the entire upstream platform may be compromised.
The Common Vulnerability Scoring System (CVSS) v3.1 base score of 6.8 reflects a Network attack vector with High confidentiality impact and High complexity. The complexity is high because the attacker must find a way to receive outbound traffic from the application and register domain names containing the victim's domain name as a substring. No user interaction is required for the leak to happen.
This vulnerability has not been observed in active exploitation in the wild, and it is not listed in CISA's Known Exploited Vulnerabilities catalog. However, the ease of exploitation once an outbound request trigger exists makes prompt remediation highly recommended. Security teams must treat any client-side cookie leakage as a high-priority exposure.
The primary recommendation is to update the http4s library to a version that implements proper RFC 6265 cookie matching. For the 0.23.x stable branch, update to version 0.23.35 or higher. For the 1.0.x milestone branch, upgrade to 1.0.0-M47 or higher.
If an immediate library upgrade is not possible, you can disable the CookieJar middleware on the client if cookie state management is not required. Avoiding the inclusion of this middleware entirely eliminates the vulnerable code path. Developers should review whether cookie tracking is strictly necessary for client-side API integrations.
Alternatively, you can implement strict outbound request filtering. Enforcing a strict domain allowlist for outbound HTTP connections prevents the client from transmitting requests to arbitrary attacker-controlled hostnames, reducing the risk of cookie exfiltration. This provides defense-in-depth against credential theft.
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:C/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
http4s-client http4s | < 0.23.35 | 0.23.35 |
http4s-client http4s | >= 1.0.0-M1, < 1.0.0-M47 | 1.0.0-M47 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-565, CWE-1275 |
| Attack Vector | Network (AV:N) |
| CVSS v3.1 Score | 6.8 (Medium) |
| EPSS Score | Negligible |
| Impact | High Confidentiality Loss (Cookie Exfiltration) |
| Exploit Status | PoC available in test suite, no weaponized exploits in wild |
| KEV Status | Not listed in CISA KEV |
The system uses information from a cookie to make security-critical decisions without validating the authority boundary of the receiver relative to the cookie's target domain.
CVE-2026-119209 is an uncontrolled resource consumption vulnerability in the pypdf Python library prior to version 6.21.3. The flaw exists within the PDF 1.5 cross-reference (XRef) stream parsing routines in pypdf/_reader.py. Due to the absence of a document-wide entry limit across chained cross-reference streams and improper validation of negative entry counts in the /Index array, an attacker can craft a compact PDF file that triggers excessive memory allocation, resulting in a Denial of Service (DoS) via MemoryError or process termination.
CVE-2026-119208 is an uncontrolled resource consumption vulnerability in the pypdf Python library prior to version 6.21.3. When processing an encrypted PDF file after successful decryption, the get_num_pages() method fails to verify whether the encryption handler has already unlocked the document. Consequently, pypdf returns the unvalidated /Count integer directly from the /Pages catalog dictionary instead of traversing and flattening the actual page tree. Attackers can supply an encrypted PDF with an artificially inflated /Count attribute to trigger excessive memory allocation and prolonged CPU usage during downstream operations such as page iteration or label resolution.
CVE-2026-119207 (GHSA-4vqv-7265-gm2w) is an asymmetric resource consumption and denial-of-service (DoS) vulnerability in the open-source Python PDF manipulation library pypdf. In versions prior to 6.21.3, the DictionaryObject.read_from_stream method fails to bound exception message lengths when encountering malformed, unclosed dictionary structures in strict mode. When nested dictionary parsing fails, each level catches the inner exception and raises a new PdfReadError initialized with the string representation (exc.__repr__()) of the caught exception. This recursive wrapping causes geometric string expansion across the call stack, enabling a minimal PDF payload of a few hundred bytes to exhaust gigabytes of heap memory and crash the host Python process.
CVE-2026-119206 is an algorithmic complexity vulnerability in pypdf prior to version 6.21.3 that causes uncontrolled CPU resource consumption when evaluating the page_labels property. Due to repeated linear scans of the PDF catalog's /PageLabels number tree from index zero for each individual page, processing a document with a large number of pages and label ranges scales quadratically. An unauthenticated attacker can supply a crafted PDF document to an application that reads page labels, resulting in prolonged execution times and denial of service.
Authlib versions 0.15 through 1.9.0 contain an authorization bypass vulnerability (CWE-639) in the RFC 7592 ClientConfigurationEndpoint implementation and its corresponding reference documentation. The framework fails to verify that the presented registration access token belongs to the target client specified in the request, and the official reference implementations for authenticate_client and check_permission omit token-to-client binding checks. Consequently, an authenticated client holding any valid registration access token can read, modify, or delete the registration metadata of arbitrary clients on the authorization server.
CVE-2026-118773 (GHSA-3g3m-2fjr-6pw4) is an uncontrolled resource consumption vulnerability in the node-glob npm package affecting versions 9.0.0 through 14.0.1. Due to missing return statements in the AbortSignal check routines within the directory traversal walker, aborted operations reject the caller promise as expected but continue executing background filesystem reads and pattern matching. Applications that rely on AbortSignal or AbortSignal.timeout() to enforce execution budgets on user-influenced glob operations remain susceptible to CPU, event loop, and disk I/O exhaustion.