Skip to content

redis codec: fix \xHH hex escape crashing on literal 'x' in inline args - #46643

Open
waterWang wants to merge 3 commits into
envoyproxy:mainfrom
waterWang:main
Open

redis codec: fix \xHH hex escape crashing on literal 'x' in inline args#46643
waterWang wants to merge 3 commits into
envoyproxy:mainfrom
waterWang:main

Conversation

@waterWang

Copy link
Copy Markdown

Fixes #46642

Root cause

InlineStringQuotedEscapeHex pushes the escape marker x into the value
string, then scans 3 characters back for the same marker. When the user's
argument already contains a literal x before a \x hex escape, the 3-back
test matches the literal x instead of the escape marker, and std::stoul
throws std::invalid_argument on an invalid hex string. The exception
escapes the filter chain (only Redis::ProtocolError is caught) and reaches
std::terminate, aborting the entire Envoy process.

Fix

  1. codec_impl.h — add inline_hex_digit_count_ member to track hex
    digits seen in the current \xHH escape.
  2. codec_impl.cc — stop pushing the escape marker into the value
    string. Track hex-digit count instead of scanning 3-back. After exactly two
    hex digits, convert and replace them with the decoded byte, matching Redis
    \xHH semantics.
  3. proxy_filter.cc — defense in depth: catch std::exception in
    onData() alongside the existing ProtocolError catch, so any future
    decoder exception maps to the downstream protocol error path instead of
    aborting the process.

Testing

  • The existing RESP codec tests pass with the refactored logic.
  • Inputs like SET key "x\x41" (literal x before hex escape) no longer
    crash; they decode the hex escape correctly.
  • Inputs with single hex digit (\x4) are left as-is (matching Redis
    behavior for incomplete escapes).
  • OOB read at s[s.size() - 3] when s.size() == 2 (first hex digit on
    a fresh escape) is eliminated by the state tracking approach.

Fixes envoyproxy#46642 — an unauthenticated client can crash any Envoy
process that exposes a 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 sequence.

The root cause: InlineStringQuotedEscape pushed the escape marker 'x'
into the value string, then scanned 3-back for the same marker. A
literal 'x' in user input triggered std::stoul on an invalid hex
string, throwing std::invalid_argument that escaped the filter chain
and reached std::terminate.

Fix: track hex-digit count with a member variable instead of pushing
the escape marker into the value string. Convert exactly two hex
digits matching Redis \xHH semantics.
Remove the escape marker 'x' push and track hex-digit count instead
of scanning 3-back in the string. This prevents std::stoul on invalid
input when the user's argument contains a literal 'x' before a \x
hex escape sequence.
Defense in depth: ensure any exception (e.g. std::invalid_argument
from std::stoul) that escapes the decoder is caught and mapped to
the downstream protocol error path instead of reaching std::terminate.
@waterWang
waterWang requested a deployment to external-contributors August 11, 2026 15:58 — with GitHub Actions Waiting
@repokitteh-read-only

Copy link
Copy Markdown

Hi @waterWang, welcome and thank you for your contribution.

We will try to review your Pull Request as quickly as possible.

In the meantime, please take a look at the contribution guidelines if you have not done so already.

🐱

Caused by: #46643 was opened by waterWang.

see: more, trace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Uncaught exception in Redis proxy inline command parser

1 participant