Skip to content

redis: fix uncaught exception in inline command hex escape parser causing full-process DoS [fj4WqyCCw3C5ShR1RfB7MoBPTpkRrBFYP1uT35g3MvT] - #46644

Open
waterWang wants to merge 2 commits into
envoyproxy:mainfrom
waterWang:fix-redis-inline-hex-escape-crash
Open

redis: fix uncaught exception in inline command hex escape parser causing full-process DoS [fj4WqyCCw3C5ShR1RfB7MoBPTpkRrBFYP1uT35g3MvT]#46644
waterWang wants to merge 2 commits into
envoyproxy:mainfrom
waterWang:fix-redis-inline-hex-escape-crash

Conversation

@waterWang

Copy link
Copy Markdown

Fixes #46642

Root cause

source/extensions/filters/network/common/redis/codec_impl.cc, DecoderImpl::parseSlice, State::InlineStringQuotedEscapeHex:

When entering the InlineStringQuotedEscapeHex state, the escape marker x was pushed into the value string. Each hex digit was then pushed one at a time, and the code checked s[s.size() - 3] == x to detect when the escape marker plus two hex digits had been accumulated. If the user argument already contained a literal x before the \xHH sequence (e.g. SET key "x\x41"), the 3-back check could match that literal x after only one hex digit, prematurely calling std::stoul on a string starting with x (e.g. "x4"), which throws std::invalid_argument. The exception was not caught (only Redis::ProtocolError is caught at the filter callsites), causing std::terminate and aborting the entire Envoy process.

Additionally, when \x was the first content of a quoted argument, after one hex digit s.size() == 2, so s[s.size() - 3] was an out-of-bounds read (operator).

Fix

  1. Parser fix (codec_impl.cc, codec_impl.h): Stop pushing the escape marker x into the value string. Instead, accumulate hex digits in a dedicated scratch buffer (inline_hex_digits_). Convert to a single byte using manual hex conversion (no std::stoul) only after exactly two hex digits are seen. A non-hex digit or end-of-quote before the second digit flushes the literal x followed by any accumulated digits, matching Redis semantics.

  2. Defense in depth (proxy_filter.cc, client_impl.cc): Add a catch (std::exception&) handler alongside the existing ProtocolError catch at both decoder callsites, so any unexpected exception from the decoder is treated as a protocol error rather than terminating the process.

  3. Tests: Added regression tests for:

    • Literal x before \xHH escape (the crash input)
    • Truncated escape (one hex digit then end of quote)
    • \x escape at the start of a quoted string (the OOB read)
    • Multiple consecutive \xHH escapes

@waterWang
waterWang deployed to external-contributors August 11, 2026 16:06 — with GitHub Actions Active
@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: #46644 was opened by waterWang.

see: more, trace.

@yanavlasov yanavlasov self-assigned this Aug 11, 2026
@yanavlasov

Copy link
Copy Markdown
Contributor

Thanks @waterWang for the PR. The change looks good to me. However it needs a couple of fixes please.

Every commit needs DCO to record the author. See here on how to fix it https://github.com/envoyproxy/envoy/pull/46644/checks?check_run_id=93843380399

Also PR needs format fix. Please run the fix the code automatically.
bazel run //tools/code_format:check_format -- fix

@yanavlasov yanavlasov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/wait

the two hex digits of a ``\xHH`` escape in a dedicated buffer and converts them only once both
are present, matching Redis semantics. A truncated escape (one hex digit before the closing
quote) is emitted literally instead of crashing, and the out-of-bounds read when ``\x`` was the
first content of a quoted argument is eliminated. No newline at end of file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
first content of a quoted argument is eliminated.
first content of a quoted argument is eliminated.

Needs newline after last sentence to be formatted correctly.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Uncaught exception in Redis proxy inline command parser

2 participants