Skip to content

feat: add max_req_body_size to bound client request body in forward-auth and ai-proxy#13466

Merged
shreemaan-abhishek merged 4 commits into
apache:masterfrom
shreemaan-abhishek:feat/forward-auth-body-size-limit
Jun 10, 2026
Merged

feat: add max_req_body_size to bound client request body in forward-auth and ai-proxy#13466
shreemaan-abhishek merged 4 commits into
apache:masterfrom
shreemaan-abhishek:feat/forward-auth-body-size-limit

Conversation

@shreemaan-abhishek

@shreemaan-abhishek shreemaan-abhishek commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Description

Several plugins read the entire client request body into memory with no upper bound, which lets a client force a worker to buffer an arbitrarily large body. The only existing backstop is the global nginx client_max_body_size, which operators routinely raise or disable for upload routes.

This adds a max_req_body_size option (integer, default 67108864 = 64 MiB, minimum 1) to the affected request-body readers, so oversized requests are rejected with 413 before the body is buffered/parsed:

  • forward-auth: caps the POST body forwarded to the authorization service (passed to core.request.get_body()).
  • ai-proxy / ai-proxy-multi: caps the body parsed for LLM proxying, enforced at the top of access().

Docs and e2e tests are included.

⚠️ Default behavior change

These plugins now default max_req_body_size to 64 MiB. The change is observable only when all of the following hold:

  1. the route uses forward-auth with request_method=POST, or ai-proxy / ai-proxy-multi; and
  2. the operator has raised nginx client_max_body_size above 64 MiB (or set it to 0); and
  3. a client sends a request body larger than 64 MiB.

In that case the request is now rejected with 413 instead of being buffered in full. Under the default client_max_body_size (1 MiB) there is no change. The limit is configurable via max_req_body_size to restore prior behavior.

Which issue(s) this PR fixes:

Fixes #

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change
  • I have verified that this change is backward compatible (see the documented default behavior change above; configurable via max_req_body_size)

When request_method is POST, the plugin reads the entire client request
body into memory to forward it to the authorization service, with no upper
bound. Add a max_req_body_size option (integer, default 1048576, minimum 1)
passed to core.request.get_body() so oversized bodies are rejected with 413
instead of being buffered without limit.
@dosubot dosubot Bot added size:M This PR changes 30-99 lines, ignoring generated files. enhancement New feature or request labels Jun 3, 2026
@membphis

membphis commented Jun 3, 2026

Copy link
Copy Markdown
Member

P1 blocker: the PR description and documentation need to explicitly document this default behavior change.

This PR adds max_req_body_size with a default of 1048576 (1 MiB). For forward-auth with request_method = "POST", request bodies larger than 1 MiB will now be rejected with 413. However, APISIX currently defaults client_max_body_size to 0 (unlimited), so this is not behavior-preserving under the existing default configuration: POST bodies larger than 1 MiB that were previously forwarded to the auth service will now be rejected by the plugin default.

Please update the PR description and the forward-auth documentation to clearly state:

  • this affects users who use forward-auth POST mode to forward large request bodies;
  • the effective default changes from unlimited to 1 MiB for this plugin path;
  • oversized requests will receive 413;
  • users need to configure max_req_body_size to a larger value to preserve the previous behavior.

…e forward-auth default

Extend the max_req_body_size request-body cap to the AI proxy plugins and
align the forward-auth default:

- ai-proxy / ai-proxy-multi: add max_req_body_size (default 67108864 = 64 MiB);
  oversized requests are rejected with 413 in access() before the body is
  parsed for LLM proxying
- forward-auth: raise the max_req_body_size default from 1 MiB to 64 MiB so
  existing large-body POST auth flows are not affected by the default

Docs and e2e tests updated.
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:M This PR changes 30-99 lines, ignoring generated files. labels Jun 3, 2026
@shreemaan-abhishek shreemaan-abhishek changed the title feat(forward-auth): support max_req_body_size to limit forwarded body feat: add max_req_body_size to bound client request body in forward-auth and ai-proxy Jun 3, 2026
@shreemaan-abhishek

Copy link
Copy Markdown
Contributor Author

@membphis addressed: the PR description now includes an explicit Default behavior change section documenting exactly when the 64 MiB default is observable, and the user-facing docs for forward-auth, ai-proxy, and ai-proxy-multi document the new max_req_body_size attribute and its default. Under the default client_max_body_size there is no behavior change.

Comment thread apisix/plugins/ai-proxy-multi.lua Outdated
membphis
membphis previously approved these changes Jun 4, 2026
AlinsRan
AlinsRan previously approved these changes Jun 4, 2026
ai-proxy/ai-proxy-multi enforced max_req_body_size by calling
core.request.get_body(max) at the top of access() and discarding the result.
get_body() does not cache, and the body is read again immediately by
detect_request_type -> get_json_request_body_table, so every request buffered
the body twice. For large AI JSON bodies (which nginx spills to a temp file)
this doubled the body read and cost ~7-9% throughput in benchmarks (1/5/10 MB).

Read the body once instead:
- core.request.get_request_body_table / get_json_request_body_table take an
  optional max_size, forwarded to their single internal get_body() call.
- ai-proxy/base.lua detect_request_type forwards the limit into that parse and
  maps an oversized body to 413 (preserving the "failed to read request body"
  log); all other read/parse failures stay 400.
- ai-proxy / ai-proxy-multi drop the read-and-discard get_body() block and run
  detect_request_type first, so oversized requests are rejected before any
  balancer / DNS / health-check work.
…ealthcheck

After moving detect_request_type to the top of the access phase, a no-body
warm-up request short-circuits with 400 before pick_ai_instance runs, so the
active health checker is never created and the unhealthy instance is not
marked down during the sleep. Send a valid body in the warm-up so it reaches
instance selection and bootstraps the checker, as before.
@shreemaan-abhishek
shreemaan-abhishek dismissed stale reviews from AlinsRan and membphis via 565793e June 9, 2026 05:16
@shreemaan-abhishek
shreemaan-abhishek merged commit 7f2953e into apache:master Jun 10, 2026
22 checks passed
wistefan pushed a commit to wistefan/apisix that referenced this pull request Jun 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants