Payment endpoints without rate limiting are the primary target of automated carding attacks: bots enumerate stolen card numbers by submitting hundreds of small charges per minute, using your checkout as a free card-validity oracle. Each probe costs you a Stripe fee ($0.05–$0.30 per declined charge), triggers fraud signals on your account, and can result in Stripe account suspension. CWE-770 (Allocation of Resources Without Limits or Throttling) captures this exact attack vector. OWASP A07 (Identification and Authentication Failures) covers the authentication-bypass aspect of unauthenticated brute-force. PCI-DSS 4.0 Req 6.4 requires that web-facing applications be protected against known attack patterns including automated attacks.
High because unthrottled payment endpoints are directly exploitable for automated carding attacks that accumulate Stripe fees, fraud signals, and potential account suspension.
Apply a sliding-window rate limit to every payment submission endpoint. Five attempts per minute per IP is a reasonable ceiling for legitimate users.
// app/api/payment/route.ts
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
import { headers } from 'next/headers'
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(5, '60 s'),
})
export async function POST(req: Request) {
const ip = (await headers()).get('x-forwarded-for') ?? 'anonymous'
const { success } = await ratelimit.limit(`payment:${ip}`)
if (!success) return new Response('Too many requests', { status: 429 })
// ... payment processing
}
For authenticated routes, layer user-ID-based limiting on top of IP limiting to catch cases where multiple IPs share the same compromised account.
ID: ecommerce-payment-security.client-side-handling.rate-limiting-payment-endpoints
Severity: high
What to look for: Count every payment API route (endpoints that create charges, intents, or process checkout submissions). For each, check for rate limiting middleware or configuration. Look for imports of @upstash/ratelimit, express-rate-limit, rate-limiter-flexible, or custom rate limiting logic. Check for Vercel Edge Config or Cloudflare rate limiting rules applied to payment routes. Also check middleware files for rate limiting applied globally or to specific route patterns matching /api/payment, /api/checkout, /api/stripe.
Pass criteria: 100% of payment submission endpoints have rate limiting applied — either per-IP, per-user, or both. Requests exceeding the limit return HTTP 429. The limit is no more than 10 payment attempts per minute per IP.
Fail criteria: No rate limiting found on any payment endpoint — no middleware, no platform-level rules, no per-user attempt counting.
Skip (N/A) when: The project uses a fully hosted payment form (Stripe Hosted Checkout, PayPal Standard) where payment endpoint access is controlled by the provider, not your backend.
Detail on fail: Describe the unprotected endpoints. Example: "POST /api/create-payment-intent has no rate limiting — automated carding attacks can attempt unlimited card-number combinations without throttling"
Cross-reference: The API Security audit covers rate limiting across all API endpoints, not just payment routes.
Remediation: Add rate limiting to payment endpoints using Upstash (works well with Vercel Edge) or a similar library:
// app/api/payment/route.ts with Upstash rate limiting
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'
import { headers } from 'next/headers'
const ratelimit = new Ratelimit({
redis: Redis.fromEnv(),
limiter: Ratelimit.slidingWindow(5, '60 s'), // 5 requests per minute
})
export async function POST(req: Request) {
const ip = headers().get('x-forwarded-for') ?? 'anonymous'
const { success } = await ratelimit.limit(ip)
if (!success) {
return new Response('Too many requests', { status: 429 })
}
// ... proceed with payment processing
}