While testing redacted.com's GraphQL API, I came across a query used to fetch team membership details names, roles, and emails of everyone on a team. Nothing unusual on the surface, since I could see my own team's data without issue.
But I wanted to know: what happens if I just change the teamId?
The Discovery
- I intercepted the request my own dashboard was making to pull up team members, and isolated the teamId argument being passed to the query. Instead of leaving it as my own team's ID, I swapped it for a different, arbitrary value — one that didn't belong to any team I was part of.
- The response came back exactly as if I'd queried my own team: a full list of members, complete with email addresses.
- There was no authorization check confirming that the requesting user actually belonged to the team being queried. The API simply trusted whatever teamId was handed to it.
Why This Matters
- This isn't a one-off leak it's a pattern that scales. If team IDs are sequential or otherwise enumerable, an attacker doesn't need to guess at random. They can iterate through IDs and systematically harvest membership data for every team on the platform: who works where, their roles, and their email addresses.
- That's a goldmine for anyone running phishing campaigns or targeted social engineering against a specific company's employees, and it's exactly the kind of data that should never be one parameter away from public exposure.
The Fix
The resolver needs to verify, server-side, that the authenticated user is actually a member of the team they're requesting data for before returning anything. Trusting a client-supplied ID without checking the requester's relationship to that object is the textbook definition of IDOR, and GraphQL APIs are no less vulnerable to it than REST.
Disclosure Timeline
Reported the vulnerability to the team, and received a response within 3 days confirming the issue and awarding a bounty of $1000.
