Login
ChallengesLearn
Scoreboard
Teams
SPNZ

LearnAPI SecurityBroken Object Level Authorization
API Security·Lesson 3 of 11

Broken Object Level Authorization

OWASP API #1. The API trusts the client to supply object IDs without verifying ownership. Change one UUID in a JSON body and see another user data — the API version of IDOR.

Intermediate14 min
APIBOLAAuthorization
Loading lesson…
PreviousAPI ReconnaissanceNextBroken Authentication

© 2026 SPNZ.

Terms of ServicePrivacy PolicyCookie Policy

Broken Object Level Authorization (BOLA) is the most critical API security risk according to OWASP. It occurs when an API trusts client-supplied object IDs without verifying that the authenticated user owns or is entitled to access the requested object. The attacker simply changes an ID in the URL, query string, or request body and receives data belonging to another user.

What you'll be able to do
  • Define BOLA and explain why it is the OWASP API #1 risk.
  • Identify BOLA in both REST and GraphQL API patterns.
  • Describe the 2021 GitLab GraphQL BOLA vulnerability and its root cause.
  • Apply mitigation strategies: ownership checks, UUIDs, and field-level authorisation.
Key terms
BOLA (Broken Object Level Authorization)
An API vulnerability where the server fails to verify that the authenticated user has permission to access the requested object. The API equivalent of IDOR, but scoped to any object type — orders, invoices, messages, projects.
IDOR (Insecure Direct Object Reference)
A vulnerability where an attacker can access or modify resources by directly referencing internal object identifiers (e.g., database IDs) that the server does not validate against the user's permissions.
Field-level authorisation
A security pattern in GraphQL where each field resolver independently verifies that the requesting user has permission to access that specific piece of data, rather than relying on a single root-level auth gate.
What is it?

When the API trusts the object ID

Imagine a REST endpoint like GET /api/users/123. The authenticated user making the request has ID 456, but the endpoint returns data for user 123 without checking ownership. This is BOLA in its simplest form. The same bug appears in GraphQL: query { user(id: 123) { ... } }. BOLA is the API equivalent of IDOR, but it extends beyond users to any object type — orders, invoices, messages, projects, or payment records. Because APIs return structured data rather than HTML pages, a missing object-level check silently leaks sensitive information without any visual indication to the user.

The root cause is almost always the same: the developer adds authentication ("is the user logged in?") but forgets authorisation ("is this user allowed to access this specific object?"). A single blanket auth middleware at the router level creates a false sense of security while every object-level endpoint remains exposed.

BOLA attack flow
Mini Map
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.
Try it

Explore the BOLA simulator

The sandbox below simulates a REST API that returns project data by ID. Toggle the BOLA check on and off to see how a missing ownership verification exposes another user's private project.

staging/api/projects/1
API Browser
GET /api/projects/:idREST endpoint

BOLA Simulator

Query a project by ID as user alice.

Response
Enter a project ID and click Query to test the API.
Access log

No requests yet.

Hint:Try querying project ID 2 or 3 with BOLA check OFF to see another user's data.
Real-world relevance

GitLab GraphQL BOLA (2021)

In 2021, GitLab disclosed a critical BOLA vulnerability in its GraphQL API. The platform exposed a resolver that allowed any authenticated user to query CI/CD variables for any project — including private projects the user was not a member of. The query was simple: project(id: N) { ciVariables { ... } }. CI/CD variables often contain API keys, database passwords, and cloud credentials. An attacker could enumerate project IDs and exfiltrate secrets from every project in the GitLab instance. The root cause was identical to the REST BOLA pattern: the resolver fetched the project by ID without verifying membership.

This incident demonstrates that GraphQL does not inherently prevent BOLA — it may even widen the attack surface by giving attackers a single endpoint through which they can query multiple object types in one request. Every resolver that accepts an object ID as an argument must independently verify access.

Mitigation

Ownership checks at every level

The fundamental fix is to never trust a client-supplied identifier without verifying ownership. Every handler or resolver that accepts an object ID must scope its database query to resources the authenticated user owns or has been granted access to.

javascriptvulnerable
// VULNERABLE — REST handler trusts the ID
app.get('/api/projects/:id', async (req, res) => {
  const project = await db.projects.findUnique({
    where: { id: req.params.id },
  });
  res.json(project);
});

// SAFE — handler filters by ownership
app.get('/api/projects/:id', async (req, res) => {
  const project = await db.projects.findFirst({
    where: {
      id: req.params.id,
      OR: [
        { ownerId: req.user.id },
        { members: { some: { userId: req.user.id } } },
      ],
    },
  });
  if (!project) return res.status(403).json({ error: 'Forbidden' });
  res.json(project);
});

// VULNERABLE — GraphQL resolver skips ownership
const resolvers = {
  Query: {
    project: (_, { id }, ctx) =>
      db.projects.findUnique({ where: { id } }),
  },
};

// SAFE — resolver checks membership
const resolvers = {
  Query: {
    project: async (_, { id }, ctx) => {
      const project = await db.projects.findFirst({
        where: { id, ownerId: ctx.user.id },
      });
      if (!project) throw new ForbiddenError('Access denied');
      return project;
    },
  },
};

Beyond ownership checks, use UUIDs instead of sequential IDs — they prevent enumeration even when authorisation is missing. Apply field-level authorisation in GraphQL resolvers, and audit every endpoint that accepts an object identifier during code review.

Further reading
  • OWASP API Security Top 10 — BOLA (API1)(OWASP)
  • CWE-639: Authorization Bypass Through User-Controlled Key(MITRE)
  • GitLab 2021 GraphQL BOLA Disclosure(GitLab)
Key takeaways

What to remember

  • BOLA is OWASP API #1 because it is pervasive and easy to miss — every endpoint that accepts an object ID is a potential target.
  • Authentication is not authorisation. A logged-in user may not own the requested object.
  • GraphQL magnifies BOLA risk because a single query can request multiple object types through different resolvers.
  • Use ownership-scoped database queries, non-sequential UUIDs, and field-level authorisation in GraphQL.
  • The 2021 GitLab incident is a textbook case: the resolver fetched a project by ID without verifying the user was a member.

Knowledge check

0/3 answered · 0 correct
  1. 1.What is the root cause of a BOLA vulnerability?

  2. 2.Why does GraphQL increase the risk of BOLA compared to REST?

  3. 3.A developer switches from sequential IDs to UUIDs. Does this fix BOLA?