Safeguard
Security Guides•

Does your GraphQL schema have a node field that skips authorization?

GraphQL node and nodes fields fetch any object by ID. Learn how to check your schema for them and why every object still needs its own authorization check.

Safeguard Security Team
4 min read

It might. Many GraphQL schemas expose node or nodes fields on the Query type that fetch any object by its ID. If the resolver behind them skips the ownership check, a caller who holds or guesses an ID can read someone else's data. Check your schema, then enforce authorization on every object.

Why these fields exist

Some GraphQL schemas follow a pattern where every object has a global ID and a single entry point can load any of them. The GraphQL project documents this as global object identification. It is handy for client caching and refetching.

It is also a second door into your data. Your carefully protected invoice(id) query may check ownership, while node(id) loads the same invoice through a different path that nobody reviewed.

OWASP's GraphQL cheat sheet describes the underlying mistake: developers assume that possession of an object's ID means the caller should have access. Failing to verify access is broken object level authorization, also known as IDOR. The cheat sheet notes that a GraphQL API can support access by ID even when that was not intended, and that there are sometimes node or nodes fields, or both, on the query object.

How to check your schema

OWASP shows a command line check, assuming schema.json holds your schema:

cat schema.json | jq ".data.__schema.types[] | select(.name==\"Query\") | .fields[] | .name" | grep node

If it prints node or nodes, you have a direct by ID entry point. In a schema you own, you can also search the schema definition file for those field names, and search the resolver code for where object loading happens.

What the fix looks like

OWASP states that removing these fields from the schema should disable the functionality, but that you should always apply proper authorization checks to verify the caller has access to the object they are requesting. Both halves matter.

  1. Decide whether any client needs node or nodes. If none does, remove them.
  2. If they are needed, route them through the same authorization function your other resolvers use. One shared check beats several copies. The GraphQL project recommends delegating authorization to the business logic layer for this reason.
  3. Check authorization on both edges and nodes. OWASP points to a bug report where nodes had no checks but edges did.
  4. Write a test that logs in as user A and requests user B's object by ID through every path, including node.
  5. Log denied requests so repeated ID guessing is visible.

Shapes of the bug

Entry pointTypical stateRisk
Named query like invoice(id)Reviewed, has checkLow
node(id)Added by a library, often unreviewedHigher
Nested field on another objectInherits parent check, sometimes notMedium
Mutation taking an IDOften checks login, not ownershipHigher

The pattern is the same everywhere: the check must be tied to the object, not to the route that reached it.

Why scanners can miss it

An automated test needs two real users with different data to notice that one can read the other's object. Without that setup, the request simply succeeds and looks normal. That is why a manual, two account test for each ID based path is worth the time.

Try it yourself

Click through it at your own pace, or open it full screen.

Look for how API findings are grouped, then ask which of your endpoints would need a two account test.

Quick check

Is a random or hard to guess ID a substitute for authorization?

No. An ID that leaks through a log, a link or another response works for any caller unless the server checks ownership on every request.

Should I delete node and nodes fields?

If no client uses them, yes, per OWASP's guidance. If they are used, keep them but apply the same authorization check as every other path.

Safeguard scans your dependencies and SBOMs for known vulnerabilities and can show which findings are reachable in your code. A free scan is at gold.safeguard.sh/scan.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.