Rate limiting: the API-key limiter is bypassable via the Authorization header, and /login/password has none
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 9.9k
- Forks
- 471
- Avg merge
- 2d 4h
- Merged PRs (30d)
- 117
Description
1. The v2/MCP limiter buckets on the raw Authorization header.
rateLimiterKeyGenerator (packages/api/src/utils/rateLimiter.ts:5) keys on req.headers.authorization verbatim, but validateUserAccessKey (packages/api/src/middleware/auth.ts:89) parses it as authHeader.split('Bearer ')[1], which accepts any prefix. One credential, unlimited bucket spellings. Jest harness, real middleware pair, max=3, 8 requests:
Bearer <key> -> 200,200,200,429,429,429,429,429
n<i> Bearer <key> -> 200 x8, same authenticated user
That defeats the 100 req/min cap on /api/v2/* and the 600 req/min on /mcp — and /mcp is where LLM agents hammer, the traffic that cap bounds. Needs a valid API key first, so DoS/cost only: no confidentiality or integrity impact.
2. POST /login/password has no limiter. Locally (API + a mongo container, our clone): 60 wrong-password attempts from one client in 1.9s, no 429, no lockout, account still usable after. The password policy is strong (12 chars, mixed case, digit, symbol), so not a break by itself; the point is asymmetry — utils/rateLimiter.ts covers /api/v2/* and /mcp, but not the one endpoint facing anonymous traffic.
Direction, not a design: key the bucket on the token the auth middleware actually parses, hashed rather than verbatim (the raw bearer secret is currently the limiter's in-memory map key), and apply a limiter to the login route. Happy to implement whichever shape you want; steer me first.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with packages/api/src/utils/rateLimiter.ts and packages/api/src/middleware/auth.ts, then trace the POST /login/password route and the existing Jest harness. Confirm that equivalent bearer credentials share a bucket and that anonymous password attempts are rate-limited, with tests covering both behaviors.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- api, authentication, security
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 54/100