I was poking around an API that my Friend built — just a simple shop backend. No fancy user interface, just raw requests. Everything looked fine at first. But then I noticed something… unfinished.

So I started testing, request by request.

And then I saw it.

Not an error. Not a crash.

😱 Something way worse.

Let me walk you through what I discovered, how I found it, and why this is one of the most dangerous API flaws in modern applications.


🚀 The Setup: API Testing with Postman

I started with the basics. I fired up Postman, added my API key and user number:

GET /api/user/2?apiKey=abc123

Boom, I got a response. The data matched my account. Everything looked normal…

…Except one thing: the response included the password in plain text.

I brushed it off — maybe it’s just test data.

But something else caught my eye.

This number in the URL:

/api/user/2

Could this number be manipulated?

So I changed the 2 to a 3.

Sent the request again:

GET /api/user/3?apiKey=abc123

💥 Boom. I got someone else’s data.

Same format. Different user. No errors. No login bypass.

I just changed a number.

That’s when it hit me.

🧠 Broken Object Level Authorization (BOLA)

I was staring at a classic vulnerability:

Broken Object Level Authorization (BOLA)

Here’s what it means:

  • The server checks if the API key is valid ✅
  • But it never checks if that key is allowed to access the requested user’s data

So with a valid key for user 2, I was able to access user 3, user 4… anyone.

🔄 Enumerating Other Users

I wanted to know: how many users could I enumerate?

So I used Burp Suite with a payload brute-force technique:

Burp Setup

  1. Copied HTTP request from Postman
  2. Pasted into Repeater
  3. Sent it to Intruder
  4. Chose Sniper attack type
  5. Set payload position to the user ID
  6. Configured numbers from 0 to 100

Sample Request Template

GET /api/user/§ID§?apiKey=abc123

I started the attack.

  • Some came back 500 Internal Server Error
  • Others came back 200 OK with full user data

📜 Names, emails, even passwords — all in plain text.

🧨 Why This Is Dangerous

Most APIs use predictable IDs like 1, 2, 3…

With no authorization check tied to the object, you can enumerate users.

It’s one of the top issues in the OWASP API Security Top 10.

This isn’t theoretical. This is real and dangerous.

🛡️ How to Fix It: Never Trust the Client

If the client says:

GET /api/user/3?apiKey=abc123

The server should never trust that the user is allowed to access user 3.

But in many APIs, that check is missing.

❌ Vulnerable Code (Broken BOLA)

@app.route("/api/user/<id>")
def get_user(id):
    api_key = request.args.get("apiKey")
    user = find_user_by_api_key(api_key)
    return get_user_by_id(id)

✅ Secure Code (BOLA Fixed)

@app.route("/api/user")
def get_authenticated_user():
    api_key = request.args.get("apiKey")
    user = find_user_by_api_key(api_key)
    if not user:
        return {"error": "Unauthorized"}, 401
    return user.to_dict()

🔐 Why This Works

  • No user ID is sent in the URL
  • The server derives the user from the API key
  • Even if the client tries to access someone else’s data, it won’t work

💡 Lessons Learned

  • Never trust input from the client
  • Always enforce access control on the server side
  • Avoid exposing predictable IDs if possible

🎯 Real-World Risk

That was just one API.

Imagine hundreds — in fintech, healthcare, education — all making the same mistake.

Unprotected. Exposed. Vulnerable.


Stay curious, stay safe. 🛡️