CriticalGraphQL IDOR → ATO· 4 min read

A Mutation With a Stranger's ID

The GraphQL mutation to edit account info trusted whatever user ID you handed it. So I handed it someone else's.

Target anonymized · a local-business reviews platform

GraphQL makes it wonderfully easy to expose a mutation and forget that "can this caller do this?" is a separate question from "is this input valid?" This reviews platform forgot exactly that, and it cost it every business account.

The spark

The mutation that edits a business user's account info took an encoded user ID in its input. That ID wasn't secret — it was sitting in the source of any public business page. Any time a write operation accepts a target ID from the client, I want to know whether it checks that the target is you.

Digging in

It didn't. I sent the mutation with a test victim's encoded ID and an email address I controlled. The response: "Successfully edited account info." The server had just changed another account's email because I asked it to.

The resolver validated that the ID was a real user. It never validated that the real user was me.

The exploit (two controlled test accounts)

mutation {
  editBizUserAccountInfo(input: {
    bizUserEncid: "<victim-encoded-id>",
    email: "attacker@example.com"
  }) { message }
}

With the victim's email now pointing at me, I opened the password-reset flow, submitted my address, received the reset link, and logged in. Zero clicks from the victim, start to finish.

Impact

Zero-click account takeover of any business account on the platform — read, write, impersonate. The kind of bug that, at scale, is an existential problem for a business-facing product.

The fix

Authorize the mutation against the authenticated caller's own account. A client-supplied ID can select what to display; it can never be allowed to decide whose account gets edited.

graphqlidoraccount-takeoverzero-click

All identifiers, targets and payloads in this post are anonymized or defanged. Findings were reported and resolved through responsible disclosure.