Skip to content

Chunked request bodies are buffered before the request timeout starts (slow-drip memory hold) #22

Description

@Coriou

Deep audit 2026-09-06, finding F5 (security, moderate). Survived refutation with amendments.

Mechanism. bodyLimit is registered before timeoutMiddleware (src/server.ts:53-63), so the per-request timeout never covers body receipt. For Transfer-Encoding: chunked bodies, Hono's body-limit middleware (4.13.3, node_modules/hono/dist/middleware/body-limit/index.js) fully buffers every chunk and only rejects once size > maxSize. The only bound on the drip phase is Bun's socket idleTimeout (derived 35s from UPVECTOR_REQUEST_TIMEOUT), which a chunk arriving every <35s re-arms indefinitely. No concurrent-request limit exists in the stack.

Trigger. Any authenticated client sends a chunked upload dribbling 1 byte per interval shorter than the idle timeout: buffered memory is held indefinitely per connection (bounded at 32 MiB by bodyLimit, but the time axis is unbounded), re-armed connection-by-connection after each 413.

Refuter amendments. Per-connection magnitude is capped at maxSize (32 MiB) — the unbounded axis is time, not per-connection GB. Content-Length bodies are unaffected (header check only; timeout covers handler-side parse). Authenticated-only.

Candidate mitigations (to assess).

  • Idle/chunk-gap timeout on body receipt (wrap the body reader before bodyLimit).
  • Global concurrent-connections or in-flight-bytes semaphore.
  • Upstream: raise with hono (body-limit buffering behavior).

Triage guidance: docs/RUNBOOK.md. Audit procedure: docs/workflows/deep-audit.md.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    deep-auditFindings from scheduled deep audits

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions