A predictable numeric user ID exposed through an authenticated endpoint made it trivial to pull any user's account data — name, email, job title, roles, and company structure — with no authorization checks.
I was exploring a Comcast internal API during a recon pass — the kind where you’re not looking for anything specific, just following the data. I authenticated normally and started mapping endpoints through Burp’s proxy.
One endpoint caught my eye:
GET /api/v1/loggedInUsers
It returned my own account information: name, email, job title, assigned roles, and company/org details. Useful for an app, normal enough. But buried in the JSON response was a numeric userId:
{
"userId": 10482,
"name": "...",
"email": "...",
"jobTitle": "...",
"roles": ["..."],
"company": "..."
}
Sequential numeric IDs in a production API are always worth a second look.
I tried something simple. Instead of hitting /api/v1/loggedInUsers, I constructed a direct resource URL:
GET /api/v1/10483
The server responded with a 200 OK and returned the full profile of another user — someone I had no business accessing. No authorization check. No ownership validation. Just a raw lookup by ID.
This is a classic Insecure Direct Object Reference (IDOR). The application was treating the user ID as both an identifier and an access token, which it isn’t.
The steps were almost embarrassingly simple:
userId from the /loggedInUsers responseBecause the IDs were sequential integers, iterating through a range would expose every user in the system. I stopped after confirming the issue with two or three IDs — no need to pull a full dump to prove impact.
A basic loop would look like:
import requests
session = requests.Session()
# ... authenticate here ...
for user_id in range(10000, 10020):
r = session.get(f"https://[redacted]/api/v1/{user_id}")
if r.status_code == 200:
print(f"[+] {user_id}: {r.json().get('email')}")
Each unauthorized profile response included:
For a large organization, that’s not just a privacy issue — it’s a social engineering gold mine. An attacker mapping internal org structure and email formats is already halfway through a phishing or pretexting campaign.
| Risk | Detail |
|---|---|
| PII exposure | Name, email, job title accessible for all users |
| Org mapping | Full company structure enumerable |
| Phishing risk | Email formats + roles = targeted social engineering |
| Compliance | Likely reportable under applicable data regulations |
The fix here is a one-liner in principle, but needs to be applied consistently across every endpoint that touches user resources.
The server must verify that the requesting user owns — or has explicit permission to access — the requested resource. The check should look something like:
if requested_user_id != current_user.id and not current_user.is_admin:
return 403
Beyond that: