Login
ChallengesLearn
Scoreboard
Teams
SPNZ

LearnAccess ControlAccess Control Case Studies
Access Control·Lesson 11 of 12

Access Control Case Studies

GitLab (2021) — GraphQL IDOR leaked private projects. Facebook (2018) — View As broke access boundaries. Capital One (2019) — SSRF + path traversal. The root cause in every case: a missing server-side check.

Intermediate18 min
Access ControlHistoryBreaches
Loading lesson…
PreviousSession ManagementNextAccess Control Review & Practice

© 2026 SPNZ.

Terms of ServicePrivacy PolicyCookie Policy

Three major access-control breaches across three different attack classes. GitLab (2021) — GraphQL IDOR leaked private project data. Facebook (2018) — the “View As” feature bypassed access boundaries on 50 million accounts. Capital One (2019) — SSRF chained with path traversal exfiltrated data on 100 million credit card applicants. Every case shares the same root cause: a missing server-side check.

What you'll be able to do
  • Map the three breaches to the access-control class they represent: IDOR, privilege escalation, and path traversal.
  • Explain how GraphQL batching amplified the GitLab IDOR.
  • Describe why a rarely-used code path bypassed Facebook's access controls.
  • Identify the SSRF + path traversal chain in the Capital One breach.
Key terms
GraphQL batching
A technique that sends multiple queries in a single request. In the GitLab breach, batching allowed the attacker to enumerate private projects by sending thousands of ID lookups in parallel.
SSRF
Server-Side Request Forgery — an attack where the attacker tricks the server into making requests to internal resources that are not directly accessible from the internet.
Access boundary
The logical separation between what one user can see and what another user or an administrator can see. A missing access boundary is the common thread across all three cases.
What is it?

Three breaches, one root cause

The common thread across the GitLab, Facebook, and Capital One breaches is not the specific technique but the absence of a server-side authorisation check. In each case, the application trusted the client to specify which resource to access — a project ID, a profile view, a metadata URL — without verifying that the requesting user had permission.

prodacme-portal.app/security/breaches/gitlab
acme-portal
Case studies
GitLab (2021)

GraphQL IDOR — any authenticated user could read private project data by supplying a numeric project ID without a membership check.

Vulnerable code
# GraphQL resolver (vulnerable)
def resolve_project(id, current_user)
  Project.find(id)
  # no membership check
end
Exploit payload
POST /api/graphql
{
  "query": "query {
    a: project(id: 1)  { name, visibility }
    b: project(id: 2)  { name, visibility }
    ...
    z: project(id: 26) { name, visibility }
  }"
}
Access log (breach in progress)
2021-08-30 14:23:01 GET /api/graphql 200 batch=26 ids=1-26
2021-08-30 14:23:03 GET /api/graphql 200 batch=26 ids=27-52
2021-08-30 14:23:05 GET /api/graphql 200 batch=26 ids=53-78
2021-08-30 14:23:07 GET /api/graphql 200 batch=26 ids=79-104
Fix commit diff
-  def resolve_project(id, current_user)
-    Project.find(id)
-  end
+  def resolve_project(id, current_user)
+    project = Project.find(id)
+    unless project.members.include?(current_user) ||
+           project.visibility == 'public'
+      raise ForbiddenError
+    end
+    project
+  end
GraphQL batching amplifies IDOR — always verify membership in the resolver, never rely on the client to scope queries.
Real-world relevance

GitLab (2021) — GraphQL IDOR at scale

GitLab disclosed a critical vulnerability in their GraphQL API that allowed any authenticated user to access private project data, including the contents of repositories in public projects with restricted issue boards. The endpoint accepted a numeric project ID and returned full project data — including the namespace, visibility level, and issue content — without checking if the user was a member of that project.

The attacker used GraphQL's batching feature to query thousands of project IDs in a single HTTP request, extracting enough data to map the entire GitLab SaaS instance. The fix was straightforward: add an ownership check that verified the requesting user was a member of the project before returning data. The case is the canonical example of how GraphQL amplifies the blast radius of a missing access check.

Real-world relevance

Facebook (2018) — “View As” boundary bypass

Facebook's “View As” feature was designed to let users see how their profile looks to a specific friend. The feature worked by temporarily elevating the friend's access level on the current user's data — but a rarely-used code path involving video uploads and birthday wishes skipped the boundary check entirely. The result: an attacker could view any account's private profile data, including phone numbers and email addresses, without permission.

Facebook's post-mortem revealed that the bug was not in the core access control system but in a single handler that deviated from the standard pattern. The fix was two-fold: patch the specific handler and audit every other endpoint for the same pattern. The takeaway: even the most mature access control systems fail when a single code path bypasses the centralised gate.

Mitigation

The fix is always a server-side check

javascriptvulnerable
// VULNERABLE - trusts client-supplied project ID
graphql resolver:
  project(root, { id }) {
    return db.projects.findUnique({ where: { id } });
  }

// SAFE - verifies membership
graphql resolver:
  project(root, { id }, { userId }) {
    const project = db.projects.findUnique({ where: { id } });
    const membership = db.members.findUnique({
      where: { projectId_userId: { projectId: id, userId } }
    });
    if (!membership && project.visibility !== 'public') {
      throw new ForbiddenError();
    }
    return project;
  }

The Capital One case adds a second lesson: path traversal and SSRF often appear together. The fix in that case was to block access to the AWS metadata endpoint (169.254.169.254) at the WAF level and to validate that user-supplied URLs resolved to approved external domains, not internal IP ranges.

Further reading
  • GitLab GraphQL IDOR Disclosure (2021)(GitLab)
  • Facebook Security Update (2018) — 50M Accounts(Facebook)
  • Capital One Data Breach 2019 — DOJ Indictment(DOJ)
Key takeaways

What to remember

  • GitLab (2021): GraphQL IDOR via missing membership check on project ID — amplified by batching.
  • Facebook (2018): “View As” access boundary bypass — one handler out of dozens was missing the check.
  • Capital One (2019): SSRF + path traversal chained to read internal metadata and assume an IAM role.
  • Every case shares the same root cause: the server trusted a client-supplied identifier without verifying ownership.
  • The fix is always a server-side authorisation check — never trust the client to specify which resource they can access.

Knowledge check

0/3 answered · 0 correct
  1. 1.Which attack class does the GitLab 2021 breach represent?

  2. 2.What made the Facebook 2018 breach particularly concerning?

  3. 3.What two vulnerabilities were chained in the Capital One 2019 breach?