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 35–38 (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