Skip to content

security: rate-limit + 16KiB body cap on public signup (TODO item 8 remainder) - #103

Closed
lopugit wants to merge 2 commits into
mainfrom
claude/service-account-rate-limit
Closed

security: rate-limit + 16KiB body cap on public signup (TODO item 8 remainder)#103
lopugit wants to merge 2 commits into
mainfrom
claude/service-account-rate-limit

Conversation

@lopugit

@lopugit lopugit commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Completes the remaining half of TODO/TODO.md item 8 (auth rate limiting): POST /api/v1/auth/register was the last anonymous auth endpoint with no throttle and no body-size cap. Login, password-reset (+confirm), and resend-verification already use enforceRateLimit, and service-account provisioning is covered by PR #100 — this PR deliberately does not touch that route to avoid overlapping with #100.

Changes

  • auth.register rate-limit rule (admin-editable via the existing panel): 20 / 15 min, keyed by IP, fail-open like other ordinary user actions. Every signup hashes a password and sends a verification email, so unmetered calls were a mass-account-creation + mail-send vector.
  • 16 KiB body cap via readJsonBody, mirroring the login route (previously raw request.json() with no bound — and body size is what bounds any persisted field sizes).

Not needed from the original TODO text: the meta mass-assignment concern is already fixed on main — the route whitelists fields and createUserAccount strips privileged meta keys at the single chokepoint.

Seeding/fixtures are unaffected: scripts/mongodb/setup.ts calls registerUser in-process, not over HTTP.

Live verification (worktree dev stack, real API)

Case Result
21 rapid signups from one IP first 20 → 200, 21st → 429 + Retry-After
>16 KiB body 413 Payload Too Large
Signup from a fresh window 200, cookie set, user created

Note for reviewers: config.ts will have a trivial adjacent-line conflict with PR #100 (both append a rule after auth.login).

🤖 Generated with Claude Code

POST /api/v1/auth/register had no throttle and no body-size cap — the
last ungated anonymous auth endpoint (login, password-reset, confirm and
resend-verification already use enforceRateLimit, and PR #100 covers
service-account). Every signup hashes a password and sends a
verification email, so unmetered calls were a mass-account + mail-send
vector.

Adds an admin-editable 'auth.register' rule (20 / 15 min / IP,
fail-open like other ordinary user actions) and caps the body at 16 KiB
via readJsonBody, mirroring the login route. Seeding and fixtures call
registerUser in-process, so they are unaffected. The meta
mass-assignment concern from the TODO is already covered: the route
whitelists fields and createUserAccount strips privileged meta keys.

Live-verified on the worktree dev stack: 20x 200 then 429 with
Retry-After; >16 KiB body 413; fresh-window signup still 200.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 21, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
thingtime Ready Ready Preview, Comment Jul 26, 2026 12:47pm

Request Review

@lopugit

lopugit commented Jul 30, 2026

Copy link
Copy Markdown
Owner Author

Consolidating the TODO 8/9/10 security PRs: #99 is the single winner and now carries this PR's unique value (see the consolidation note on #99 for exactly what was folded in and why). Closing as a duplicate.

@lopugit lopugit closed this Jul 30, 2026
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.

1 participant