security: bound Zod inputs, add SSE per-user cap and tRPC body limit (#51) #59

Merged
Hartmut merged 1 commits from security/zod-audit-51 into main 2026-04-18 13:53:28 +02:00
Owner

Closes #51 (except the ESLint rule + conventions doc follow-ups).

Summary

  • Apply .max() bounds across 9 router schemas (IDs 64, names 200, search 500, arrays 100–5000 by domain).
  • Tighten webhook secret to min(16).max(256) and url to max(2048).
  • Validate reports/allocations query params via zod (year bounds, end>=start) and restrict format to pdf/xlsx.
  • Add per-user SSE connection cap (8) in /api/sse/timeline with 429 + Retry-After.
  • Reject tRPC request bodies over 2 MiB via Content-Length header check before auth/DB work.

Test plan

  • pnpm test:unit (1945 API + 321 engine + 195 application tests pass)
  • pnpm --filter @capakraken/web exec tsc --noEmit
  • pnpm --filter @capakraken/api exec tsc --noEmit
  • pnpm lint (0 errors)
  • Smoke: login, load timeline (SSE), fire an allocations export

🤖 Generated with Claude Code

Closes #51 (except the ESLint rule + conventions doc follow-ups). ## Summary - Apply `.max()` bounds across 9 router schemas (IDs 64, names 200, search 500, arrays 100–5000 by domain). - Tighten webhook `secret` to `min(16).max(256)` and `url` to `max(2048)`. - Validate reports/allocations query params via zod (year bounds, end>=start) and restrict `format` to `pdf`/`xlsx`. - Add per-user SSE connection cap (8) in /api/sse/timeline with 429 + Retry-After. - Reject tRPC request bodies over 2 MiB via Content-Length header check before auth/DB work. ## Test plan - [x] `pnpm test:unit` (1945 API + 321 engine + 195 application tests pass) - [x] `pnpm --filter @capakraken/web exec tsc --noEmit` - [x] `pnpm --filter @capakraken/api exec tsc --noEmit` - [x] `pnpm lint` (0 errors) - [ ] Smoke: login, load timeline (SSE), fire an allocations export 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Hartmut added 1 commit 2026-04-18 13:31:37 +02:00
security: bound Zod inputs, add SSE per-user cap and tRPC body limit (#51)
CI / Architecture Guardrails (pull_request) Successful in 2m6s
CI / Lint (pull_request) Successful in 7m29s
CI / Typecheck (pull_request) Successful in 8m3s
CI / Unit Tests (pull_request) Successful in 8m11s
CI / Build (pull_request) Successful in 5m24s
CI / E2E Tests (pull_request) Successful in 5m25s
CI / Fresh-Linux Docker Deploy (pull_request) Successful in 6m30s
CI / Release Images (pull_request) Has been skipped
CI / Assistant Split Regression (pull_request) Successful in 3m47s
40ca0c3046
Mechanical .max() bounds across 9 router schemas per the convention in
#51: IDs at 64, names at 200, search/filter strings at 500, arrays at
100-5000 depending on domain. Webhook secret bounded at min(16)/max(256).

Reports route now validates startDate/endDate via zod with year bounds
and rejects end<start. SSE timeline route enforces a per-user connection
cap of 8 (returns 429 with Retry-After). tRPC route rejects bodies over
2 MiB via Content-Length check before auth/DB work.

Covers 12 call-sites listed in #51. ESLint rule and zod conventions doc
remain as follow-up.
Hartmut merged commit 17471af7f8 into main 2026-04-18 13:53:28 +02:00
Hartmut deleted branch security/zod-audit-51 2026-04-18 13:53:29 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Hartmut/CapaKraken#59