Email me

Explainer · 9 min read

Filed under App development

What is IDOR? The bug that lets anyone read your users' data by changing one number

Short answer

IDOR (insecure direct object reference) is when your app takes an ID from the request, say /invoices/1043, and returns that record without checking the logged-in user is allowed to see it. Change the number to 1044 and you are reading a stranger's invoice. Guessable IDs make it easier to exploit, but they are not the bug: the missing ownership check is. Random IDs slow a guesser down; one condition in the query shuts the door.

Bar chart titled Missing-authorization CVEs, by year published. CVEs tagged CWE-639 (IDOR) or CWE-862 (missing authorization) in NVD: 2017 56, 2018 71, 2019 256, 2020 309, 2021 282, 2022 493, 2023 645, 2024 283, 2025 118, 2026 through October 24 1,227.
Published CVEs tagged with the two missing-authorization weaknesses, by year. 2026 already has more than any full year we pulled. Our NVD API pull, Oct 25 2026; every count is in the data file on this page. Chart by Tensorust from the NVD API.

Part of the article Pick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%. This page answers one question from it in depth.

On this page · 11 sections
  1. Key numbers
  2. What IDOR looks like
  3. The 885-million-file version
  4. Are guessable IDs the problem?
  5. What the CVE record shows
  6. How to fix it
  7. Common misconceptions
  8. What this means for you
  9. Related
  10. FAQ
  11. Sources

The current fear is that AI-written apps leak data. Some do. But the most famous IDOR on record came from one of the biggest US title insurers in 2019, built by humans, and it exposed about 885 million files. The bug is old, boring and fixable in one line, whoever wrote the code.

Key numbers

What Number Source (checked Oct 25 2026)
OWASP Top 10 rank of broken access control (IDOR's category) #1 in 2021 and 2025 OWASP Top 10 2025, A01
Applications tested with some form of it, 2021 / 2025 94% / 100% 2021 A01, 2025 A01
Occurrences in OWASP's data, 2021 / 2025 318,487 / 1,839,701 same
First American files exposed, no login needed about 885 million, going back 16+ years KrebsOnSecurity, May 24 2019
SEC penalty for First American $487,616 SEC, June 15 2021
CVEs tagged CWE-639 or CWE-862, 2026 through Oct 24 1,227 (vs 645 in all of 2023) our NVD API pull, Oct 25 2026
Their share of all CVEs published in 2026 1.38% of 88,641 same
Fresh random bits per UUIDv7, by library 32 to 74 (UUIDv4: 122) our UUIDv7 library test, Oct 23 2026

What IDOR looks like

Three ingredients, per the OWASP IDOR cheat sheet: an object (an account, a document, a ticket), a reference to it in the URL or request body, and a server that never asks whether this user may touch that object.

Two code panels. Left, in orange, titled IDOR: trusts the ID: GET /api/invoices/1043 handled by get_invoice, which loads db.invoices.get(id) and returns it, so a user logged in as user 7 reads user 12's invoice by typing 1044, 1045. Right, in green, titled Fixed: checks the owner: the same endpoint loads the invoice by id and owner equal to the current user's id and returns 404 when nothing matches. The whole bug and the whole fix. Same URL, same ID scheme, one extra condition. Diagram by Tensorust.

The login works. The session is valid. The user is exactly who they say they are. That is why IDOR slips past people: authentication passed, authorization was never asked. MITRE files it as CWE-639, Authorization Bypass Through User-Controlled Key. PortSwigger notes the term was popularized by the OWASP Top Ten back in 2007. In API security, OWASP renames it BOLA (broken object level authorization) and ranks it API1:2023, with exploitability, prevalence and detectability all rated easy or widespread.

The 885-million-file version

On May 24, 2019, real estate developer Ben Shoval showed KrebsOnSecurity that a document link First American Financial had emailed him worked for everyone. Changing the document number "in either direction yielded other peoples' records", Krebs wrote, suggesting the numbers were issued sequentially. The earliest went back to 2003. No authentication was required. The files included bank account numbers, wire records and Social Security numbers.

Follow the money afterward. The SEC's 2021 order was about disclosure controls, not the bug itself: First American's senior executives were not told that the company's own security staff had found the vulnerability several months earlier and had not fixed it. The penalty was $487,616. For a company of that size, the price of 16 years of customer files sitting one number apart was a rounding error. Nobody is coming to save your users; the check has to be in your code.

Are guessable IDs the problem?

Partly, and this is where people over-learn the lesson. Sequential IDs turn IDOR from a bug into a free download: add 1, repeat. Random IDs raise the cost of guessing. Our UUIDv7 library test measured how many fresh random bits each popular library puts in every ID once an attacker knows the creation millisecond:

Horizontal bar chart titled How many bits an ID guesser has to beat. Fresh random bits per ID once the creation millisecond is known: auto-increment integer 0, Rust uuid, Python standard library and uuid-utils 32, npm uuidv7 and Rust uuid7 32, npm uuid v7 42, PyPI uuid7 48, Go google/uuid v7 62, .NET CreateVersion7 and PyPI uuid6 74, UUIDv4 122. Fresh random bits per ID, measured on 1 million IDs per library, Oct 23 2026. UUIDv4's 122 bits are from RFC 9562. Every row is in the parent article's data.

32 bits is 4,294,967,296 possibilities. At 1,000 guesses a second, sweeping them takes about 49.7 days per millisecond of creation time, and a rate limit stretches that further. So UUIDs do stop the "add 1" attack. That is real.

What they do not stop is everything else. IDs leak: in shared links, invoice emails, browser history, analytics, support screenshots, referrer headers and logs. First American's own customers were emailed working links. The moment an ID is known, randomness is worth zero. That is why RFC 9562 says implementations "SHOULD NOT assume that UUIDs are hard to guess" and "MUST NOT" use them as security capabilities, and why OWASP's cheat sheet says access control checks stay "essential" even with complex identifiers. Pick UUIDv7 or UUIDv4 for your database's sake. Do not pick them for security.

What the CVE record shows

We counted every CVE in the NVD tagged CWE-639 (the IDOR entry) or CWE-862 (missing authorization), by year published, through October 24, 2026.

  • 2026 so far: 1,227 missing-authorization CVEs (285 CWE-639, 942 CWE-862), already almost double the busiest full year we pulled, 2023 at 645.
  • That is 1.38% of the 88,641 CVEs published this year, against 2.08% in 2023. The share is not exploding; the whole CVE pile is. NVD published 49,972 CVEs in all of 2025 and 88,641 in 2026 through October 24.
  • 2024 and 2025 dipped to 283 and 118. A CWE tag depends on who filed and analyzed each record, so treat single-year swings with care.

Our read: more software is shipping, and more people and tools are hunting for exactly this bug, because it is the cheapest one to find. A researcher with two test accounts finds it in an afternoon. That cuts both ways: whoever ships faster gets found faster.

How to fix it

  1. Scope every lookup to the user. Query by the object's ID and the current user's ID (or team, or role) together. No match returns 404, so you do not even confirm the record exists.
  2. Do it on the server, on every endpoint. Reads, updates, deletes, exports, file downloads, GraphQL resolvers and background job triggers. Hiding a button in the UI is not a check.
  3. On Supabase, turn on row-level security. Its docs say that once RLS is enabled, no data is accessible through the API with a publishable key until you create policies. Without it, the auto-generated API is an IDOR on every table.
  4. Take the user from the session, never from the request. OWASP's BOLA page warns that just comparing a user ID in the token to an ID in the URL covers only a small subset of cases; look up what that user actually owns. Our JWT decoder shows which user a token claims to be.
  5. Test with two accounts. Log in as user A, copy an ID, log in as user B, paste it. Do that for every object type. It takes minutes and it is the test that finds this bug.

Common misconceptions

Myth

"We use UUIDs, so we are safe."

The recordUUIDs stop sequential guessing, not leaked links. RFC 9562 itself says not to treat them as hard to guess, and the 32-bit libraries in our test give a guesser far less to beat than the 122 bits people assume.

Myth

"Users have to log in first, so it is fine."

The recordIDOR is a logged-in bug. The attacker is a normal user reading other users' data. Authentication answers who you are, not what you may open.

Myth

"This is an AI-code problem."

The recordThe OWASP data found broken access control in 94% of tested apps in 2021, before AI app builders went mainstream, and the biggest IDOR on record was hand-built. AI tools ship the same mistake faster; they did not invent it.

Myth

"Only APIs have IDOR."

The recordFile downloads, PDF links, image URLs and admin pages all carry object references. First American's leak was document images.

What this means for you

Before you launch, open your app in two browsers with two accounts and swap every ID you can find between them. If anything loads that should not, fix the query, not the ID format. If your app is built on Lovable, Bolt or Supabase and you would rather have someone else do this, our $49 Launch Check checks whether a stranger can read your tables, plus storage, logins and secret keys, in plain English within 48 hours; if a problem in what we checked turns up after your report, we write the fix at no extra cost.

FAQ

What is an IDOR vulnerability?

IDOR stands for insecure direct object reference. It happens when an app takes an ID from the request, such as /invoices/1043, and returns that record without checking that the logged-in user is allowed to see it. Changing the number to 1044 shows someone else's data. MITRE files it as CWE-639, Authorization Bypass Through User-Controlled Key.

Do random IDs like UUIDs prevent IDOR?

They make guessing harder, not impossible, and they do nothing once an ID leaks through a shared link, an email, a log or a browser history. OWASP's IDOR cheat sheet says access control checks are essential even with complex identifiers, and RFC 9562 says UUIDs must not be used as security capabilities.

How do you fix IDOR?

Check ownership or permission on every request, on the server, for every object: look the record up by its ID and the current user's ID together, and return 404 when there is no match. In Supabase, that means row-level security policies on every exposed table. Then test with two accounts by swapping IDs between them.

Is IDOR the same as broken access control?

IDOR is one kind of broken access control, which ranks number 1 in the OWASP Top 10 for both 2021 and 2025. In the 2025 edition, 100% of the applications tested had some form of broken access control. In API security, OWASP calls the same bug BOLA, broken object level authorization, and ranks it API1.

What was the First American IDOR breach?

In May 2019, developer Ben Shoval and KrebsOnSecurity found that First American Financial's site exposed about 885 million title insurance files, going back more than 16 years, with no login. Changing the document number in a link showed other people's records. The SEC later fined the company $487,616 over its disclosure controls.

Sources

All checked October 25, 2026.

Standards and rankings

The First American case

Our data

  • NVD CVE API 2.0 (docs): totalResults for cweId CWE-639, cweId CWE-862 and all CVEs, by publication date in quarterly windows, 2016 to October 24, 2026, pulled October 25, 2026. Every count is in data.csv on this page.
  • Random bits per ID: Pick a UUIDv7 library that keeps order, 1,000,000 IDs per library, October 23, 2026. Guessing time is our arithmetic (2^32 at 1,000 guesses a second).

Images

  • Charts and code diagram by Tensorust from the data above.

Next question

Every number on this page links to its source and was checked on Oct 25, 2026. Spot an error or a newer figure? Email matt@tensorust.com and it gets fixed. Related: $49 Launch Check for Lovable, Bolt and Supabase apps, JWT decoder (see which user a token claims).

Read next

Back to The Manual →   All articles →

Get the next one by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Up next

The article this answer comes fromPick a UUIDv7 library that keeps order: 10 tested, .NET fails 50%We tested 10 UUIDv7 libraries with 1M IDs each and a clock jump. .NET put 50% out of order, uuid6 ran 16.6 min ahead. The 2 that passed, plus free data.Read it next →

Get the receipts by email.

What my AI agents tried this week, with the real numbers: what worked, what flopped, what made money. One email when there is something worth reading.

No spam, never sold. Every email has a one-click unsubscribe.

Cite this

Free to cite and reuse under CC BY 4.0 with a link back. How it was collected: methods. Spotted an error? Corrections.

Did this answer your question?

Popular in the shop

All 124 tools →

Browse: Bundles and kitsHome, family and schoolMoney and businessAI toolsSports and fitnessMaking and hobbiesFood and drinkIndie dev and launchTrading and quant

Free: Landing page teardown iPhone app cost calculator LLM API cost calculator Paid online: $49 Launch Check App builds Articles FAQ

Disagree, or have a number to add? Discuss this on The Floor →

What are people saying about this? Read and post on The Floor →