← HomeBlog

2026-09-09 · Application security

GitLab GraphQL unauthenticated access: what scanners miss in your API

GitLab shipped an emergency patch on August 17, 2026, five days after a routine release that carried no critical issues. The Hacker News reported the same day: CVE-2026-19478, CVSS 9.4, a GraphQL flaw that under certain conditions lets an unauthenticated attacker modify or delete public projects and user data.

That is not remote code execution. It is an authorization failure on a public GraphQL surface. For a SaaS team, that is the more familiar bug.


What GitLab confirmed

GitLab described the issue as an unauthenticated user remotely modifying or deleting public projects and user data via a GraphQL directive. The company did not name the directive or the exact conditions. The CVSS vector says network-exploitable, no credentials, no user interaction.

Fixes landed in GitLab 19.2.4, 19.1.6, 19.0.8, and 18.11.11. GitLab.com and GitLab Dedicated were already patched. Self-managed installs from 18.2 onward in the affected branches still need to move. The 18.2 through 18.10 lines sit inside the affected range and did not get a backport.

A second issue in the same release, CVE-2026-19650 (CVSS 7.1), is CSRF in the GraphQL multiplex query handler. It needs user interaction. GitLab said it had not seen exploitation of either flaw as of the disclosure, and no public exploit was on GitHub as of August 18.

Technical write-ups for both issues go public on GitLab's tracker about 90 days after the patch, around mid-November.


Why a GraphQL scanner still reports clean

GraphQL puts many operations behind one endpoint. Authorization has to hold on every mutation and, often, on every field. A directive that runs outside the usual resolver path can skip the check your middleware was supposed to enforce.

Automated scanners tend to hit /api/graphql, note a 200 or a 401, try a few injection strings, and move on. They do not walk every mutation as an anonymous client, then as the wrong tenant, then with a crafted directive.

That is the same gap we test in SaaS GraphQL APIs. Introspect the schema (or rebuild it from error traffic if introspection is off). List mutations that create, update, or delete. Run each one with no token. Check whether public resources are treated as "anyone may write." Then check field-level arguments: can an authenticated user set a tenant they do not own?

GitLab's public-project boundary is the lesson. Public does not mean consequence-free. A public repo still holds CI config, issue threads, and commit history that a deleted or poisoned project can wreck. If that repo feeds a build, write access without a login is a supply-chain problem, not a documentation problem.


What to test on your own GraphQL API

If you run a multi-tenant product on GraphQL, do the unauthenticated pass yourself before the next audit.

Call every mutation with no credentials. Repeat with a valid session for a different tenant. Confirm that public or shared resources still require an explicit write grant. Treat custom directives as their own auth surface, not as decoration on a resolver you already checked.

The GitLab case is a reminder that a mature platform with a security team still missed an unauthenticated write on a public object. Your schema is smaller. The failure mode is the same.


At Faultline Security we run web application penetration tests for European B2B SaaS companies, including GraphQL authorization and tenant isolation. If you want that unauthenticated pass done before someone else finds the mutation, get in touch.