Skip to content

security: reject oversized request bodies, document file attachments - #122

Merged
shrdgn merged 1 commit into
mainfrom
claude/vibrant-archimedes-1geom4
Jul 26, 2026
Merged

security: reject oversized request bodies, document file attachments#122
shrdgn merged 1 commit into
mainfrom
claude/vibrant-archimedes-1geom4

Conversation

@shrdgn

@shrdgn shrdgn commented Jul 26, 2026

Copy link
Copy Markdown
Owner

What & why

  • Server-side request body size limit. Nothing in the server previously bounded request body size — limits.py caps concurrency and rate (max_in_flight, rate_limit_per_minute, both off by default), but a single request of any size was read fully into memory via await request.json(). This matters more now that the playground's file-attachment feature (shipped in feat: file attachments + live panel progress counter in playground #107) sends multimodal payloads with base64-encoded file/image content — the UI enforces a 10 MB client-side cap, but nothing stops a direct API client from sending an arbitrarily large body and exhausting memory before the rate limiter even sees the request.
  • Adds limits.max_request_bytes (off/unlimited by default, consistent with the other limits.py knobs) and server.py::MaxBodySizeMiddleware, which checks Content-Length against the cap and returns a clean 413 before the body is read, in the same OpenAI-compatible error shape as the rest of the API.
  • Best-effort like the rest of limits.py: a client that omits Content-Length (chunked transfer-encoding) or lies about it isn't caught by this check — documented as a follow-up in docs/ARCHITECTURE.md's security table, same pattern used for the existing concurrency/rate-limit row.
  • Docs: the file-attachment feature itself (paperclip button, 10 MB limit, supported types) was shipped but never mentioned in README's Playground section — added a short bullet documenting it while touching this area.

How it was tested

  • ruff check . passes
  • pytest -q passes (no live network) — 473 passed (was 469; 4 new tests: oversized body → 413 + upstream never called, request within limit passes, unlimited by default preserves current behavior, malformed Content-Length header falls through rather than raising)
  • New behavior has a test (tests/test_limits.py)
  • Docs updated (README "Production limits" + "Playground", docs/ARCHITECTURE.md security table, CHANGELOG.md, examples/preset.yaml.example)
  • No secrets, prompts, or response bodies added to logs or metrics
  • N/A — no quality/cost claim, nothing for bench/run.py
  • mypy openfusion/ --ignore-missing-imports --disable-error-code import-untyped --exclude openfusion/cli.py — clean, 23 source files
  • pytest --cov=openfusion — 99.53% overall, no regressions; new middleware fully covered

Notes for reviewers


Generated by Claude Code

- Add limits.max_request_bytes (off/unlimited by default): rejects a
  request whose Content-Length exceeds the cap with 413 before the body
  is read into memory (server.py::MaxBodySizeMiddleware). Nothing
  server-side previously bounded request size, which matters now that
  the playground's file-attachment feature can send large multimodal
  payloads directly to the API, bypassing the UI's client-side 10 MB
  check.
- Document the new setting in README/ARCHITECTURE.md's security table/
  CHANGELOG/example config, and document the file-attachment feature
  itself in README's Playground section (shipped but never documented).

Found via an automated repo-quality review.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Mdwk4pysKSkFrAMG7P5y1V
@shrdgn
shrdgn merged commit d653e7d into main Jul 26, 2026
3 checks passed
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