Securealy
Check · Security · medium · verified

Endpoints are rate limited

Ten rapid requests to one endpoint produce a 429 or equivalent.

Severity
medium
Tier
Verified: after you prove ownership
Category
Security
Fix
Summary below; full runbook in the Fix Kit, Module 03: Lock it down
Id
rate-limit

What this means

Passing means an endpoint answers a short burst of rapid requests with a 429 or an equivalent refusal. Failing means ten quick requests were all served, which tells us nothing stands between a script and your endpoint but your hosting bill. Sign-in endpoints and anything that calls a paid API on each request are where this bites first.

How we test it

This check runs after you verify ownership (DNS TXT _securealy, the securealy-verify meta tag, or /.well-known/securealy.txt). We send ten requests to one endpoint in quick succession and watch for a 429 or an equivalent refusal. Pass is a refusal appearing within the ten. Fail is ten served responses. It is a bounded probe of a fixed count, never a loop, and the only check where we make more than one request to the same path.

Why it matters

Unmetered endpoints turn into runaway bills and brute force. Supabase publishes rate limits for email, OTP and token refresh, but there is no limit on password sign-in attempts and failed attempts are logged nowhere you can see, so an endpoint that proxies sign-in without its own counter lets someone grind passwords against a real employee's address. On the cost side, the Fix Kit exists partly because an unbounded request loop ran for eight days against an endpoint backed by a paid warehouse and cost $425; an unmetered endpoint lets a stranger run that loop against you.

The fix

Put the limit in the shared gate so every endpoint inherits it: Module 3's gate.js refuses with a 429 and a Retry-After header once a caller passes its per-window count, and for sign-in Module 5 proxies the password grant through your own endpoint and counts failures from your access log, 8 per email and 40 per IP in 15 minutes. The in-memory skeleton is a speed bump on serverless hosts, so count from a store that instances share, as the Module 5 throttle does. The full runbook is in the Fix Kit, Module 03.

Prompt for your AI

Paste this into the coding agent that built the app. It reproduces the finding and stops before changing anything; the fix steps are in the kit.

Read the handler for https://YOUR_DOMAIN/api/YOUR_ENDPOINT and every middleware it passes through, and tell me where, if anywhere, a request count per IP or per user is kept and what happens when it is exceeded.
Send exactly ten requests to that endpoint, one second apart, using a for loop with a fixed count of 10 and never an until or while loop, and print the status code of each.
Report whether any response was a 429 and whether a Retry-After header was present.
Tell me which endpoints accept a password, create a checkout, or call a paid third-party API on each request; those need a limit first.
Do not add or change any code; list what it would take to add a shared limit and stop.
Show me the ten status codes as one line; expected for a passing project: at least one 429 before the tenth request.

Next

Grade your own URL

Every grade lists this check with its evidence for your site. Two free grades a day.