GHSA-3g8r-4pfx-jmfh Netty: STOMP CONNECT Frame Header Injection in Netty
Security Vulnerability Report: STOMP CONNECT Frame Header Injection in Netty1. 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 DescriptionThe 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 CauseIn `StompSubframeEncoder.java`, the `shouldEscape()` method (lines 214-216) explicitly excludes CONNECT and CONNECTED commands from escaping:When `shouldEscape()` returns `false`, header values are written without any escaping (line 195):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 AnalysisThe 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:Header values in CONNECT frames are **neither escaped nor validated** for newlinesA raw newline in a header value creates a **new header line** on the wireThe STOMP broker parses each line as a separate headerThe fix should **validate** (reject `\n`) rather than **escape** (convert `\n` to `\\n`), maintaining spec compliance4. Exploitability PrerequisitesThis vulnerability is exploitable when **all** of the following conditions are met:The application uses Netty's `codec-stomp` module to encode STOMP framesUser-controlled input is placed into header values of a `CONNECT` or `CONNECTED` frameThe application does **not** perform its own newline sanitizationThe 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 credentialsWeb-to-STOMP bridge applications (e.g., WebSocket-STOMP proxies) where login/passcode come from web formsMulti-tenant STOMP platforms where tenant-specific headers are injected into CONNECT frames5. Attack ScenariosScenario 1: Authentication Bypass via Header InjectionAn attacker who can control any header value in a CONNECT frame can inject additional authentication-related headers:**Wire format sent to broker:**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 HijackingThis overwrites the `host` header, potentially redirecting the connection to an attacker-controlled STOMP broker (depending on broker implementation).Scenario 3: Header Overwrite**Wire format:**Some brokers use the last value when duplicate headers exist, allowing the attacker to escalate to the `admin` account.6. Proof of ConceptFull Runnable PoC Source Code (StompConnectHeaderInjectionPoC.java)How to Compile and RunPoC Execution Output (Verified on Netty 4.2.12.Final)Key ObservationThe PoC demonstrates a clear inconsistency:**CONNECT** command: `\n` is written **raw** → header injection succeeds**SEND** command: `\n` is escaped to `\\n` → header injection prevented7. 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 BrokersThis 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 headers8. Remediation RecommendationsOption 1: Validate CONNECT Header Values (Recommended)Add newline validation for CONNECT/CONNECTED frames instead of skipping escaping entirely:Option 2: Apply Escaping to All CommandsSimply remove the CONNECT/CONNECTED exception: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)
CVSS v3.1 score: 6.5