fix(server): cap request bodies and import decompression #35

Merged
nalum merged 1 commit from fix/request-body-caps into main 2026-08-13 11:41:01 +00:00
Owner

Stacked on #30 (fix/setup-window).

Request caps: no WithReadMaxBytes existed anywhere — an unauthenticated POST to Login with a huge body was a pre-auth memory-exhaustion vector. Survey showed the only large legitimate REQUEST is ImportData's archive (single-digit-MiB gzipped at family scale). Eleven services now cap at 4 MiB; SystemService alone gets 64 MiB. http.MaxBytesHandler (65 MiB) wraps the mux as a transport-level backstop covering /mcp, which is not a Connect handler.

Import decompression: maxImportBytes 1 GiB → 128 MiB (the pod limit is 256Mi; the comment itself said archives are megabytes). LimitReader enforcement unchanged; a ~130 KiB bomb expanding to 129 MiB refuses with the existing named error.

Tests mount the real server.Handler: oversized Login → ResourceExhausted; 8 MiB import passes the size gate; 64 MiB+1 KiB import refused; normal traffic untouched. Integration suite (export/import round-trips, MCP) passes.

Fixes #11

🤖 Generated with Claude Code

Stacked on #30 (`fix/setup-window`). **Request caps:** no `WithReadMaxBytes` existed anywhere — an unauthenticated POST to Login with a huge body was a pre-auth memory-exhaustion vector. Survey showed the only large legitimate REQUEST is ImportData's archive (single-digit-MiB gzipped at family scale). Eleven services now cap at 4 MiB; SystemService alone gets 64 MiB. `http.MaxBytesHandler` (65 MiB) wraps the mux as a transport-level backstop covering `/mcp`, which is not a Connect handler. **Import decompression:** `maxImportBytes` 1 GiB → 128 MiB (the pod limit is 256Mi; the comment itself said archives are megabytes). LimitReader enforcement unchanged; a ~130 KiB bomb expanding to 129 MiB refuses with the existing named error. Tests mount the real `server.Handler`: oversized Login → `ResourceExhausted`; 8 MiB import passes the size gate; 64 MiB+1 KiB import refused; normal traffic untouched. Integration suite (export/import round-trips, MCP) passes. Fixes #11 🤖 Generated with [Claude Code](https://claude.com/claude-code)
fix(server): cap request bodies and import decompression
All checks were successful
check / go (push) Successful in 2m0s
check / web (push) Successful in 1m24s
ec7ab4c82b
No handler set WithReadMaxBytes, so Connect would stage a request
message of any size in memory before the auth interceptor ran — the
public setup-window endpoints made that a pre-auth memory-exhaustion
vector. Every service now reads at most 4 MiB per message (real bodies
are kilobytes); SystemService alone gets 64 MiB because ImportData
legitimately carries a gzipped backup archive, and family-scale
archives compress to single-digit MiB. Export archives travel in
responses, which ReadMaxBytes does not touch. An http.MaxBytesHandler
just above the biggest allowance backstops the whole mux, covering the
/mcp endpoint that no Connect option reaches.

The import decompression cap drops from 1 GiB to 128 MiB: against a
256Mi pod, allowing a kilobyte-sized gzip bomb to inflate to a
gigabyte was an OOM kill waiting on an anonymous caller. 128 MiB is
still an order of magnitude past any real archive.

Fixes #11
nalum force-pushed fix/request-body-caps from ec7ab4c82b
All checks were successful
check / go (push) Successful in 2m0s
check / web (push) Successful in 1m24s
to 00ce6ffa5b
Some checks failed
tag / tag (push) Has been cancelled
check / web (push) Successful in 1m33s
check / go (push) Successful in 1m49s
2026-08-13 11:33:34 +00:00
Compare
nalum changed target branch from fix/setup-window to main 2026-08-13 11:33:56 +00:00
nalum scheduled this pull request to auto merge when all checks succeed 2026-08-13 11:34:10 +00:00
nalum merged commit 00ce6ffa5b into main 2026-08-13 11:41:01 +00:00
nalum deleted branch fix/request-body-caps 2026-08-13 11:41:01 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
eagraiclainne/app!35
No description provided.