Skip to content

[Prover] Enforce a maximum request body size when reading POST bodies - #123

Open
JoshLind wants to merge 1 commit into
mainfrom
cursor/limit-request-body-size-cee7
Open

JoshLind wants to merge 1 commit into
mainfrom
cursor/limit-request-body-size-cee7

Conversation

@JoshLind

Copy link
Copy Markdown
Contributor

What is the change being pushed?

The prover service now enforces a maximum request body size when reading POST bodies. Oversized requests are rejected with a 413 Payload Too Large instead of being buffered into memory. The limit is configurable via a new max_request_body_size_bytes config field (1 MiB by default).

Why are you pushing this change?

This was reported for the pepper service in aptos-core (keyless/pepper/service), but the prover service here has the identical flaw:

  • POST /v0/prove called hyper::body::to_bytes(request_body) to fully buffer the request body before JSON parsing, with no Content-Length cap and no streaming size limit.
  • hyper 0.14.x imposes no such default, and there is no tower body-limit layer in the dependency set.
  • The service binds 0.0.0.0 with no access-control middleware, and no authentication precedes the body-buffering call.

So any client that can reach the prover service port could stream an arbitrarily large Transfer-Encoding: chunked body and exhaust process memory, crashing the service.

How is this implemented?

  • Added handler::read_request_body_with_limit, which replaces the unbounded hyper::body::to_bytes call. It first rejects bodies whose declared length (from Body::size_hint().upper(), i.e. Content-Length) already exceeds the limit, then reads the body chunk-by-chunk with HttpBody::data() and aborts as soon as the accumulated bytes would exceed the limit. This second check is what bounds chunked bodies of unknown length. The buffer is grown on demand and is never pre-allocated from the client-declared length.
  • Added ProverServiceError::PayloadTooLarge and handler::generate_payload_too_large_response, so oversized bodies return 413 while malformed bodies keep returning 400.
  • Added ProverServiceConfig::max_request_body_size_bytes, defaulting to 1 MiB. Existing config files keep working, since the field falls back to the default.
  • Added tests covering a body exactly at the limit (still a 400 for invalid JSON), a body one byte over the limit (413), a streamed body of unknown length that is never fully read (413), and direct unit coverage of the limited reader.

Note that /v0/prove is the only POST endpoint on this service; bodies on other methods/paths are never buffered.

Type of change

Prover service change?

  • Bug fix
  • Tests

Checklist

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I identified and added all keyless stakeholders and component owners affected by this change as reviewers
  • I tested both happy and unhappy path of the functionality
  • I have made corresponding changes to the documentation

Slack Thread

Open in Web Open in Cursor 

The prove endpoint buffered the entire request body into memory via
hyper::body::to_bytes, with no cap on the body size. Since the service
is bound on all interfaces and performs no authentication before
reading the body, any client could stream an arbitrarily large chunked
body and exhaust the service memory.

Request bodies are now read through a size-limited reader that rejects
oversized bodies with a 413, both from the declared body length and
while streaming chunks of unknown length. The limit is configurable via
max_request_body_size_bytes (1 MiB by default).

Co-authored-by: Josh Lind <JoshLind@users.noreply.github.com>
@JoshLind
JoshLind marked this pull request as ready for review August 12, 2026 21:17
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