Rate limiting middleware imported is actually applied
Why it matters
Constructing an @upstash/ratelimit or express-rate-limit instance and never calling .limit() or app.use(rateLimit(...)) leaves your endpoints open to credential stuffing, enumeration, and API cost amplification. CWE-400 (Uncontrolled Resource Consumption) is the direct mapping. The library's presence in package.json signals the developer anticipated abuse — but without invocation, every endpoint accepts unlimited requests. An attacker who discovers the rate limiter is never called can run brute-force or scraping at full speed.
Severity rationale
High because an unapplied rate limiter provides zero protection against brute-force, credential stuffing, and API resource exhaustion on every route.
Remediation
Call .limit() per request at the top of each handler, or apply rateLimit() as global middleware. For Upstash:
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
const limiter = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(10, '10 s'),
})
export async function POST(req: Request) {
const ip = req.headers.get('x-forwarded-for') ?? 'anonymous'
const { success, remaining } = await limiter.limit(ip)
if (!success) {
return Response.json({ error: 'Too many requests' }, { status: 429 })
}
// ... rest of handler
}
For sensitive routes (login, password reset, signup), apply tighter limits than general API routes. Verify the .limit() call appears before any business logic.
Detection
-
ID:
rate-limiter-imported-and-applied -
Severity:
high -
What to look for: When any rate-limiting library is in
package.jsondependencies —express-rate-limit,@upstash/ratelimit,rate-limiter-flexible,rate-limit-redis,bottleneck,next-rate-limit,@vercel/firewall— walk source files and count all imports of these libraries. For each import, count whether the same file or another file in the application chain contains an INVOCATION pattern:app.use(rateLimit(,await ratelimit.limit(,await rateLimit.check(,await rateLimiter.consume(,bottleneck.schedule(, OR a middleware wrapper that the library documents. -
Pass criteria: A rate-limiting library is imported AND at least 1 invocation call exists. Report: "Rate limiter: [name] imported in [file] AND invoked in [file]."
-
Fail criteria: A rate-limiting library is imported but never invoked anywhere in source.
-
Skip (N/A) when: No rate-limiting library in dependencies AND no
vercel.json/netlify.toml/Cloudflare config defines rate limits. -
Detail on fail:
"@upstash/ratelimit imported in src/lib/ratelimit.ts but no .limit(... call found anywhere in source. Rate limiter constructed but never used to actually limit requests." -
Remediation: A rate limiter that's never invoked doesn't limit anything. Wire it into your route handlers:
// Bad: limiter constructed but never called import { Ratelimit } from '@upstash/ratelimit' const limiter = new Ratelimit({ ... }) // ...no .limit() calls anywhere // Good: invoke .limit() per request export async function POST(req: Request) { const ip = req.headers.get('x-forwarded-for') ?? 'anonymous' const { success } = await limiter.limit(ip) if (!success) { return Response.json({ error: 'Too many requests' }, { status: 429 }) } // ... handle request }
External references
- cwe · CWE-400 — Uncontrolled Resource Consumption
- owasp:2021 · A04 — Insecure Design
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ai-slop-security-theater·automated