Skip to content

fix(api): harden request parsing against panics and oversized bodies (EN-1201)#107

Merged
flemzord merged 2 commits into
mainfrom
fix/api-input-hardening
Jun 12, 2026
Merged

fix(api): harden request parsing against panics and oversized bodies (EN-1201)#107
flemzord merged 2 commits into
mainfrom
fix/api-input-hardening

Conversation

@flemzord

@flemzord flemzord commented Jun 11, 2026

Copy link
Copy Markdown
Member

Problem (High — H3, H4)

  • H3parsePageSize called panic(err) on a non-numeric pageSize (?pageSize=abc). With no recoverer middleware mounted, net/http aborted the connection (client reset) instead of returning a 400. Negative and unbounded values were also passed straight to the ledger (resource amplification). Affects all four list endpoints.
  • H4 — no request body size limit. The audit middleware (httpaudit) does io.ReadAll(r.Body) with no cap and buffers both request and response in memory → memory-exhaustion DoS, triggerable even unauthenticated.

Fix

  • parsePageSize returns an error instead of panicking; rejects < 1 and clamps to maxPageSize (100). List handlers return 400 VALIDATION on bad input.
  • Add middleware.Recoverer at the top of the chain (safety net for residual panics).
  • Apply http.MaxBytesReader (1 MiB) ahead of the audit middleware.

Tests

  • TestParsePageSize: empty→default, value, clamp >100, and errors on abc/0/-5.
  • TestListHandlerRejectsInvalidPageSize: GET /wallets?pageSize=abc → 400.

From the in-depth repository review.

parsePageSize panicked on a non-numeric pageSize (e.g. ?pageSize=abc) and
the router had no recoverer, so the client got a reset connection instead
of a 400. Negative and unbounded page sizes were also passed straight to
the ledger.

- parsePageSize returns an error instead of panicking; reject < 1 and clamp
  to maxPageSize (100); list handlers return 400 VALIDATION on bad input
- add middleware.Recoverer as a safety net
- cap request bodies with http.MaxBytesReader (1 MiB) ahead of the audit
  middleware, which buffers the whole body, to prevent memory-exhaustion DoS

Adds unit tests for parsePageSize bounds and a list handler 400 case.
@flemzord flemzord requested a review from a team as a code owner June 11, 2026 07:53
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@flemzord, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 9 minutes and 33 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 135f3765-2a2c-43f1-9c41-865989fc188b

📥 Commits

Reviewing files that changed from the base of the PR and between 85e1d3f and 7545f1b.

📒 Files selected for processing (7)
  • pkg/api/handler_balances_list.go
  • pkg/api/handler_holds_list.go
  • pkg/api/handler_transactions_list.go
  • pkg/api/handler_wallets_list.go
  • pkg/api/router.go
  • pkg/api/utils.go
  • pkg/api/utils_test.go
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/api-input-hardening

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@flemzord flemzord changed the title fix(api): harden request parsing against panics and oversized bodies fix(api): harden request parsing against panics and oversized bodies (EN-1201) Jun 11, 2026

@flemzord flemzord left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Revue inline: le plafond de body protège la mémoire, mais le chemin d’erreur renvoie encore un mauvais statut.

Comment thread pkg/api/router.go Outdated
r.Use(middleware.Recoverer)
r.Use(func(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
r.Body = http.MaxBytesReader(w, r.Body, maxRequestBodyBytes)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avec ce placement, un body trop gros est bien plafonné, mais il ressort en 500. httpaudit.Middleware lit r.Body avec io.ReadAll avant le handler et transforme toute erreur non-EOF en http.StatusInternalServerError; MaxBytesReader renvoie justement *http.MaxBytesError au-delà de 1 MiB. Un client qui dépasse la limite reçoit donc 500 failed to read request body au lieu de 413 Request Entity Too Large. Il faudrait gérer ce cas avant l’audit, ou faire traiter *http.MaxBytesError spécialement par l’audit, avec un test >1 MiB.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 7545f1b. Replaced http.MaxBytesReader with a limitRequestBody middleware that reads the body bounded to maxRequestBodyBytes+1, returns 413 REQUEST_TOO_LARGE on overflow, and resets the buffered (≤1 MiB) body so the audit middleware/handlers can still read it. This avoids the audit io.ReadAll → 500 path you flagged. Added TestRequestBodyTooLarge (>1 MiB → 413).

Address review feedback: http.MaxBytesReader surfaced its overflow error
through the audit middleware's io.ReadAll, which maps any non-EOF read error to
500 — so a >1 MiB body returned "500 failed to read request body" instead of
413. Replace it with a limitRequestBody middleware that reads the body bounded
to maxRequestBodyBytes+1, rejects oversize with 413 (REQUEST_TOO_LARGE), and
resets the (bounded) body for the audit middleware and handlers.

Adds TestRequestBodyTooLarge (>1 MiB → 413).
@flemzord flemzord merged commit 310805e into main Jun 12, 2026
6 checks passed
@flemzord flemzord deleted the fix/api-input-hardening branch June 12, 2026 07:56
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