Attack Patterns · 2 of 5

Enumeration with No Rate Limit: When a Single Guessable ID Lets You Scan the Whole Database

Published September 6, 2026 · secureFlows

This is the second post in a series on the most common attack patterns. After broken object-level authorization (where changing one number in the URL is enough) comes the pattern that almost always sits next to it: when nothing stops a script from trying thousands of numbers in a row.

Illustration of a laptop running a script that guesses sequential IDs (GET /users/1001, 1002…), a server labeled No Rate Limit, and an open vault spilling user cards with 200 OK responses, illustrating enumeration with no rate limit
One guessable ID can lead to a targeted breach. System entry points with no rate limit can, in that situation, let an attacker scan the entire database.

What Is "Enumeration with No Rate Limit", Really?

Most records in an app have an ID: a user number, a card number, a national ID, sometimes even a phone number. When those IDs are sequential or guessable (1001, 1002, 1003, or national ID numbers in a known range), an attacker only needs to know what one valid request looks like. From there they write a short loop that tries the next number, and the one after that, and the one after that.

If the server returns data for every ID that exists, and nothing limits how many requests you can send per minute, that small flaw becomes a full walk of the database. Security people call this enumeration (or ID enumeration): listing every existing ID and pulling whatever is attached to it. Rate limiting is exactly the barrier that keeps that loop from running freely.

Note the difference from pattern 1: there, one foreign ID is enough to read one other person's record. Here the story is scale: the same weakness, thousands of times per second, until the whole list is in the attacker's hands.

How It Actually Happens

Suppose you have a "verify card" or "password reset by national ID" screen. The client sends a number, and the server returns a name and phone number, "to confirm it's really you." Now imagine a script that does exactly the same thing, only with a sequential list of numbers:

Diagram: the enumeration-with-no-rate-limit bug A script sends three requests with different ID numbers. The server returns 200 OK with name and phone for each one, with no slowdown or block. Script id=318…001 id=318…002 id=318…003 Requests/sec: Unlimited Server In DB? ✓ Rate limited? ✗ Returns immediately 200 · name + phone Record 1 200 · name + phone Record 2 200 · name + phone Record 3 And so on, until the attacker's list is complete
The same innocent endpoint, thousands of times. With no rate limit there is no practical difference between "one check" and "copying the whole database."

The misleading part: sometimes there is a login check, and sometimes even a partial ownership check, but if you can discover which IDs exist and what is attached to them at high speed, you can still build a full list. And often you do not even need to log in: a public "reset" or "verify" endpoint that returns too much information is enough.

An Example from the Press

In April 2025, TheMarker (Captain Internet) reported a breach in a ticket system shared with the IDF: it was possible to guess national ID numbers and receive in return the name and phone number of active career soldiers, including senior officers, because nothing limited the rate of attempts. No sophisticated database break-in was required; a loop and a list of guessable numbers were enough.

The same pattern showed up outside Israel too: in November 2025 TechCrunch reported on U.S. state jury-management systems with sequential IDs and no limit on login attempts, which let someone scan sensitive personal records. And in December 2025, a "secure" messaging app with no limit on guessing phone numbers.

Read the article on TheMarker →

How to Fix It

There is no single magic button: there are layers that need to work together:

Diagram: the fix · server-side rate limiting The same consecutive requests, but this time the server allows a few attempts and then returns 429 Too Many Requests. Script id=…001 id=…002 id=…003 id=…004 Keeps trying… Server Counts requests by IP / account Over threshold → 429 200 · allowed (limit) 200 · still under limit 429 Too Many Requests
Same loop, this time the server counts and slows down. The scan stops long before the whole database walks out the door.

Note: hiding the ID on the client, or "not publishing the API," is not a fix. A script does not need a pretty screen. It needs a URL that works. The defense has to be on the server, on every attempt, even if it comes from a rotating IP or many accounts.

How to Check If Your App Is Exposed to This Pattern

This check is short, and worth doing on every screen that accepts an ID or phone number:

  1. Find an endpoint that accepts an ID (password reset, card lookup, profile by number).
  2. Manually send a few requests with nearby IDs (or phones in sequence) and see if useful data comes back.
  3. If it does, try at a higher rate (even with a simple tool or short script). If the server keeps answering with 200s with no slowdown and no 429, you have found the pattern.
  4. Also check what comes back when the ID does not exist: a different response ("not found" vs "SMS sent") can itself leak who exists in the system.

If within a minute or two you already have dozens of records in hand, do not wait for the next headline. Fix the rate first, then how much information each response returns.

How secureFlows Solves This From the Start

In secureFlows, access to data is based on the user's session token, not on a sequential ID your app puts in the URL. There is no "loop over user numbers" that opens other people's records, because the record is bound to the token holder from the start.

In addition, sensitive auth paths are protected with server-side rate limiting, so a guessing script cannot run freely against entry points. When you build on that infrastructure, you do not have to remember to add this barrier on every reset screen separately: it is part of the layer every request passes through.

secureFlows logo

Want user isolation and rate limiting built into the infrastructure, instead of depending on a developer's memory? Hit the button below and start building with secureFlows.

Start Building for Free