Checking if your GitLab instance is vulnerable to CVE-2026-19478

I walked through how to check if a self-hosted GitLab instance is vulnerable to CVE-2026-19478, a critical unauthenticated GraphQL injection.

Checking if your GitLab instance is vulnerable to CVE-2026-19478
Photo by Vong Vathanak / Unsplash

A few days ago GitLab disclosed CVE-2026-19478, a CVSS 9.4 vulnerability in the GraphQL layer. No authentication needed, no user interaction. Just a single GraphQL query that can delete public projects or modify user data.

I manage a self-hosted GitLab instance for our team. I wanted to check if we were affected. Here is how I did it, so you can follow the same steps on your own instance.

What the vulnerability is in one paragraph

The bug is in a GitLab GraphQL feature called @gl_introduced. This directive is used for version gating. When you query a field with @gl_introduced(version: "999.0.0"), GitLab creates a fallback field and calls Ruby's public_send on the database object using the field name as the method name. An attacker can call any zero-argument method on Project or User objects, like destroy or deactivate.

The PoC is available at davkharrr/cve-2026-19478-poc. It has a safe check mode that only calls touch (updates a timestamp, no damage).


Step 1: Check your GitLab version

First, check if your version falls in the affected range. The vulnerable versions are:

  • 18.x: 18.2.0 up to 18.11.11
  • 19.0: up to 19.0.8
  • 19.1: up to 19.1.6
  • 19.2: up to 19.2.4

Our instance was on a version squarely in the affected range. If you are already on 18.11.11 or later, you are patched.

Step 2: Run the PoC in check mode

The PoC has a safe mode that just calls touch. It does not modify or delete anything. I ran it against our instance with a known username:

python3 poc.py --url https://<your-gitlab-url> --user <username> --mode check

The output:

[*] Could not determine GitLab version (proceeding with exploit attempt).
[*] Target object : user:<username>
[*] Method invoked: touch
[*] Query:
query {
  user(username: "<username>") {
    username
    touch @gl_introduced(version: "999.0.0")
  }
}

[*] HTTP 200
[!] Parent object is null -> project/user not found or not visible.

The important parts: HTTP 200 means the GraphQL endpoint is reachable. But the parent object was null, meaning the user was not exposed to unauthenticated queries. That is a good sign.

You can also try against a project path:

python3 poc.py --url https://<your-gitlab-url> --project group/project-name --mode check

If you get "touch": true, the instance is vulnerable. If you get Field 'touch' doesn't exist on type 'Project', you are patched. If you get Parent object is null, the project is not publicly accessible.

Step 3: Check if public projects are allowed

This is the key check. The vulnerability only works on public projects (or public users). If you do not have public projects, the attack surface is closed.

I checked our instance settings using the admin API:

curl -s --header "PRIVATE-TOKEN: <admin-token>" \
  "https://<your-gitlab-url>/api/v4/application/settings" | grep restricted_visibility_levels

The response:

"restricted_visibility_levels": ["internal", "public"]

This means both internal and public visibility levels are blocked on our instance. No one can create a public project. Every project is private by force.

Step 4: Confirm no public projects exist

Even with the setting above, I wanted to confirm there are no existing public projects:

curl -s --header "PRIVATE-TOKEN: <admin-token>" \
  "https://<your-gitlab-url>/api/v4/projects?visibility=public&per_page=100"

The response was an empty array:

[]

No public projects. If you run this command and get results, those projects are targets.

What I found

Our instance was not exploitable for unauthenticated attacks. The reasons:

  • The GraphQL endpoint is reachable, but that alone is not enough.
  • Public projects are blocked globally by restricted_visibility_levels.
  • User profiles are not exposed to unauthenticated GraphQL queries.
  • No public projects exist on the instance.

The vulnerability exists in the code, but it is not reachable without authentication on our setup.


What you should check on your own instance

If you have a self-hosted GitLab instance, here is what I recommend:

  1. Check your version. If you are below the fixed versions, plan an upgrade.
  2. Run the PoC in check mode against a public project or user.
  3. Check your restricted_visibility_levels setting. If public is not in the list, consider adding it.
  4. Enumerate public projects. If any exist, they are attack targets.

The restricted_visibility_levels setting is what saved us. In our case, public and internal were already blocked for other reasons. It turned out to be the best defense against this CVE.

If you do have public projects and cannot patch immediately, consider a WAF rule that blocks requests containing @gl_introduced in the GraphQL body. The fix versions are 18.11.11, 19.0.8, 19.1.6, and 19.2.4.