Skip to content

fix(msgpack): Recursion limit#6212

Open
jjbayer wants to merge 3 commits into
masterfrom
test/msgpack-recursion-stack-overflow
Open

fix(msgpack): Recursion limit#6212
jjbayer wants to merge 3 commits into
masterfrom
test/msgpack-recursion-stack-overflow

Conversation

@jjbayer

@jjbayer jjbayer commented Jul 10, 2026

Copy link
Copy Markdown
Member

Impose a recursion limit of 128 on message pack deserialization.

Closes INGEST-990.

jjbayer and others added 2 commits July 10, 2026 14:09
The msgpack attachment path (extract_attached_event) deserializes an
Event with rmp_serde, which enforces no recursion limit (unlike
serde_json's 128-level cap). A ~200 KB payload of nested arrays, well
under the 1 MiB max_event_size, drives Value deserialization ~200k
frames deep and overflows the stack.

The proof re-execs the test binary in a child process and asserts it is
killed by a stack overflow, since the overflow aborts the process and
cannot be caught in-thread.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
rmp_serde enforces a recursion limit, but its default (1024) is too high
for Relay's deeply generic types such as Annotated<Value>: each recursive
deserialization frame is several KB, so a maliciously nested msgpack
payload exhausts the thread stack and aborts the process well before the
built-in counter trips. The max_event_size check (1 MiB) does not help,
since nesting depth is unbounded far below the byte limit.

Cap nesting at 128 (the same depth serde_json enforces by default) on all
user-facing msgpack deserialization paths: attached events, msgpack
breadcrumbs, replay video events, and event-id extraction. Deeply nested
payloads are now rejected with an error instead of crashing.

Invert the proof-of-vulnerability test into a regression test that asserts
graceful rejection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@linear-code

linear-code Bot commented Jul 10, 2026

Copy link
Copy Markdown

INGEST-990

Comment thread relay-server/src/processing/errors/errors/utils/attachment.rs Outdated
Comment thread relay-server/src/processing/errors/errors/utils/attachment.rs Outdated
Comment thread relay-server/src/processing/errors/errors/utils/attachment.rs Outdated
Comment thread relay-server/src/processing/errors/errors/utils/attachment.rs Outdated
Comment thread relay-server/src/utils/serde.rs Outdated
Comment thread CHANGELOG.md Outdated
Co-authored-by: Joris Bayer <jjbayer@gmail.com>
@jjbayer jjbayer marked this pull request as ready for review July 10, 2026 14:41
@jjbayer jjbayer requested a review from a team as a code owner July 10, 2026 14:41
let payload = item.payload();
let mut deserializer = rmp_serde::Deserializer::new(payload.as_ref());
// rmp_serde's default limit (1024) is too high for our types.
deserializer.set_max_depth(crate::utils::MSGPACK_MAX_DEPTH);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We could make a function in the utils which must be used to construct the Deserializer which will also always have the limit applied.

Then we can put rmp_serde on the shit list.

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.

2 participants