Files
Kordant/piolium/findings/p8-004-rate-limit-substring-bypass/report.md
2026-05-29 09:03:47 -04:00

49 lines
2.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
Phase: 8
Sequence: 004
Slug: rate-limit-substring-bypass
Verdict: VALID
Rationale: Rate limiting sensitive path detection uses substring matching (path.includes) with incomplete sensitive list; sensitive operations like darkwatch.runScan and voiceprint.analyzeAudio get standard tier (100/min) instead of stricter limits
Severity-Original: medium
Severity: medium
PoC-Status: pending
Pre-FP-Flag: none
Debate: piolium/attack-surface/balanced-chamber-summary.md
## Summary
The rate limiting middleware in `web/src/server/api/utils.ts` detects sensitive paths using `path.includes(p)` where `p` is from a hardcoded list of sensitive operation names (`["login", "signup", "forgotPassword", "resetPassword"]`). This substring matching is imprecise and the sensitive list is incomplete — it only covers auth-related operations. Sensitive operations like `darkwatch.runScan` (triggers expensive external API calls), `voiceprint.analyzeAudio` (processes audio through ML), and `spamshield.classifySMS` get the standard `authenticated` tier (100/min) instead of a stricter `sensitive` tier (3/hr).
## Location
- `web/src/server/api/utils.ts` lines 3538 (rate limiting middleware)
## Attacker Control
Any authenticated user can call sensitive operations at the higher rate limit (100/min) since they are not in the sensitive path list. The attacker does not need to craft special procedure paths — they simply use normal operations that are not covered by the sensitive list.
## Trust Boundary Crossed
Rate limiting policy boundary. The rate limiter applies different limits based on operation sensitivity, and the incomplete sensitive list allows operations that should be rate-limited to proceed at higher rates.
## Impact
Resource exhaustion and cost abuse for sensitive operations:
- `darkwatch.runScan` can be called 100 times/min instead of 3/hr, triggering expensive external API calls (HIBP, SecurityTrails, Censys, Shodan)
- `voiceprint.analyzeAudio` can be called 100 times/min, consuming memory and CPU for ML processing
- Service disruption for other users on the same server
## Evidence
```typescript
const sensitivePaths = ["login", "signup", "forgotPassword", "resetPassword"];
const effectiveTier = sensitivePaths.some((p) => path.includes(p)) ? "sensitive" : tier;
```
## Reproduction Steps
1. Authenticated user calls `darkwatch.runScan` with a watchlist item
2. The procedure path `"darkwatch.runScan"` does not contain any sensitive path substring
3. Rate limiter assigns `authenticated` tier (100/min) instead of `sensitive` tier (3/hr)
4. User can trigger 100 scans per minute, each triggering 5+ external API calls
5. Cumulative cost and resource impact affects all users
## Defense Search Results
- `path.includes(p)` substring matching is imprecise
- Sensitive list only covers auth-related operations
- `rateLimitedProcedure` middleware is not applied to all procedures
- No default sensitive tier for write operations (mutations)
- No IP-based rate limiting as secondary dimension