You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Verified live against official images: envoyproxy/envoy:v1.35-latest (1.35.13) and envoyproxy/envoy:v1.39-latest (1.39.0 release build) — both abort with exit code 133 after a single packet.
Description
Summary
An unauthenticated client can crash any Envoy process that exposes a envoy.filters.network.redis_proxy listener by sending a single inline Redis command containing a double-quoted argument with a literal x followed by a \x hex escape. The parser throws std::invalid_argument (from std::stoul), which escapes the filter chain (only Redis::ProtocolError is caught), unwinds through libevent C frames, and reaches std::terminate, aborting the entire Envoy process — all workers, all listeners, all in-flight traffic.
s.push_back(buffer[0]); // append one hex digitif (s[s.size() - 3] == 'x') { // checks 3-back for the escape markerchar c = static_cast<char>(std::stoul(&s[s.size() - 2], nullptr, 16));
...
}
The escape marker 'x' itself is pushed onto the value string when entering the state, so after one hex digit the completion test scans 3 characters back and can match a literal'x' that was already part of the user's argument. It then calls std::stoul on a string starting with the escape-marker x, which throws std::invalid_argument.
Exception sinks catch only Common::Redis::ProtocolError (anEnvoyException): redis_proxy/proxy_filter.cc:467-471 and common/redis/client_impl.cc:309. The exception reaches source/exe/terminate_handler.cc:36 ("std::terminate called! Uncaught unknown exception") and the process aborts (observed exit code 133 under Docker).
Secondary latent defect on the same line: when \x is the first content of a quoted argument, after one hex digit s.size()==2, so s[s.size()-3] == operator[](SIZE_MAX) — a 1-byte out-of-bounds read immediately before the string storage (fixed offset, currently benign; fix in the same patch).
Reproduction (100% deterministic, pre-AUTH, no backend needed)
redis-envoy.yaml,
# Minimal Envoy config exposing the redis_proxy filter for F1 verification.# Listener 16379 -> redis_proxy -> (declared cluster unused by the crash path;# the bug fires during inline-command decode, before any upstream dispatch).admin:
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }static_resources:
listeners:
- name: redis_16379address:
socket_address: { address: 0.0.0.0, port_value: 16379 }filter_chains:
- filters:
- name: envoy.filters.network.redis_proxytyped_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.redis_proxy.v3.RedisProxystat_prefix: redis_statssettings:
op_timeout: 5sprefix_routes:
catch_all_route:
cluster: redis_backendclusters:
- name: redis_backendtype: STATIClb_policy: ROUND_ROBINload_assignment:
cluster_name: redis_backendendpoints:
- lb_endpoints:
- endpoint:
address:
socket_address: { address: 127.0.0.1, port_value: 9999 }
Trigger variants (all crash): GET "x\x4", PING "ax\xff", any quoted argument containing a literal x before a \x<hexdigit> sequence in an inline command.
Impact & attack surface
Remote, unauthenticated denial of service of the entire Envoy process from a single packet, on any deployment fronting Redis with envoy's redis_proxy (common in Kubernetes cache tiers and service meshes). The parser runs on raw client bytes before authentication, before routing, and requires no backend Redis at all. The Redis RESP codec currently has no oss-fuzz coverage (no dedicated fuzz target or uber-fuzzer inclusion), which explains why the bug survived >2 years and 5 release trains.
Suggested fix
In InlineStringQuotedEscapeHex, stop pushing the escape marker into the value; track hex-digit count and convert exactly two hex digits (matching Redis \xHH semantics).
Defense in depth at the two filter callsites: catch std::exception alongside ProtocolError and map to the existing protocol error path.
Add the RESP codec to oss-fuzz. We have a working harness ready to contribute as a PR after disclosure (decoder-only, split delivery, seed corpus incl. this shape).
Credits
[morph3] , I would like to submit a PR fixing this as well !
Originally reported by @morph3
Affected versions
Description
Summary
An unauthenticated client can crash any Envoy process that exposes a
envoy.filters.network.redis_proxylistener by sending a single inline Redis command containing a double-quoted argument with a literalxfollowed by a\xhex escape. The parser throwsstd::invalid_argument(fromstd::stoul), which escapes the filter chain (onlyRedis::ProtocolErroris caught), unwinds through libevent C frames, and reachesstd::terminate, aborting the entire Envoy process — all workers, all listeners, all in-flight traffic.Root cause
source/extensions/filters/network/common/redis/codec_impl.cc,DecoderImpl::parseSlice,State::InlineStringQuotedEscapeHex:The escape marker
'x'itself is pushed onto the value string when entering the state, so after one hex digit the completion test scans 3 characters back and can match a literal'x'that was already part of the user's argument. It then callsstd::stoulon a string starting with the escape-markerx, which throwsstd::invalid_argument.Trace for input
SET key "x\x41":s="x"(literal) → escape'x'pushed (s="xx") → hex digit'4'(
s="xx4") →s[0]=='x'true →stoul("x4")→ throw.Exception sinks catch only
Common::Redis::ProtocolError(anEnvoyException):redis_proxy/proxy_filter.cc:467-471andcommon/redis/client_impl.cc:309. The exception reachessource/exe/terminate_handler.cc:36("std::terminate called! Uncaught unknown exception") and the process aborts (observed exit code 133 under Docker).Secondary latent defect on the same line: when
\xis the first content of a quoted argument, after one hex digits.size()==2, sos[s.size()-3]==operator[](SIZE_MAX)— a 1-byte out-of-bounds read immediately before the string storage (fixed offset, currently benign; fix in the same patch).Reproduction (100% deterministic, pre-AUTH, no backend needed)
redis-envoy.yaml,docker logs -f 12,
Trigger variants (all crash):
GET "x\x4",PING "ax\xff", any quoted argument containing a literalxbefore a\x<hexdigit>sequence in an inline command.Impact & attack surface
Remote, unauthenticated denial of service of the entire Envoy process from a single packet, on any deployment fronting Redis with envoy's redis_proxy (common in Kubernetes cache tiers and service meshes). The parser runs on raw client bytes before authentication, before routing, and requires no backend Redis at all. The Redis RESP codec currently has no oss-fuzz coverage (no dedicated fuzz target or uber-fuzzer inclusion), which explains why the bug survived >2 years and 5 release trains.
Suggested fix
InlineStringQuotedEscapeHex, stop pushing the escape marker into the value; track hex-digit count and convert exactly two hex digits (matching Redis\xHHsemantics).std::exceptionalongsideProtocolErrorand map to the existing protocol error path.Credits
[morph3] , I would like to submit a PR fixing this as well !