Gitlab EE DoS by sending unauthenticated requests via POST /api/graphql (another bypass of Json validation middleware)

⚠️ Please read the process on how to fix security issues before starting to work on the issue. Vulnerabilities must be fixed in a security mirror.

HackerOne report #3367019 by a92847865 on 2025-10-02, assigned to @gandrews7:

Report | Attachments | How To Reproduce

Report

NOTE! Thanks for submitting a report! Please note that initial triage is handled by HackerOne staff. They are identified with a HackerOne triage badge and will escalate to the GitLab team any. Please replace all the (parenthesized) sections below with the pertinent details. Remember, the more detail you provide, the easier it is for us to triage and respond quickly, so be sure to take your time filling out the report!

Summary

In latest release (v18.4.1), Json validation middleware was introduced by this security merge request. Now there're instance limits for depth, size and complexity (number of total elements) of HTTP request body (with mime-type: :json). I have submitted a bypass in which an attacker sets content-type header to application/xml (or other types except json).

The issue here is different. Malicious Json payload is totally within the limits enforcing by Json validation middleware. But a param (of type String) is parsed later by a Json parser causing uncontrolled resource consumption.

A normal json payload sending to /api/graphql looks like:

{"operationName":"abc", "query":"def","variables":{"var1":<value1>, "var2":<value2>}}  

But "variables" could also be a String:

{"operationName":"abc", "query":"def","variables":"{\"var1\":<value1>, \"var2\":<value2>}"}  

When parsing requests to get params (operationName, query and variables), an instance of GraphqlController will call Gitlab::Graphql::Variables.new(variable_info).to_h to build variables from variable_info:

https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/controllers/graphql_controller.rb#L296

 def build_variables(variable_info)  
    Gitlab::Graphql::Variables.new(variable_info).to_h  
  end  

If variable_info is a String, it will be parsed by JSON parser in this line.

So an attacker can embed a complex Json string inside "variables" value, passing Json validation check. Handling some malicious requests concurrently will consume all RAM in Gitlab EE instance.

Please be noted that /api/graphql endpoint is unauthenticated.

Steps to reproduce

(Step-by-step guide to reproduce the issue, including:)

  1. Get 2 GCP VM: VM1 (8 vCPU, 16 GB RAM) and VM2 (minimal specs)
  2. Install Gitlab EE on VM1 (https://docs.gitlab.com/install/package/ubuntu/)
  3. Generate payload (baddd.json) using badddjson.py
  4. Upload baddd.json.gz to VM2 and run: gunzip baddd.json
  5. From VM2, send 3-4 requests to Gitlab EE instance on VM1 concurrently (see more in PoC video):
curl -v 'http://<Gitlab_host_name>/api/graphql' -v   -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36'   -H 'accept: */*'   -H 'content-type: application/json'   -H 'x-gitlab-version: 18.4.1-ee'   --data-binary [@]baddd.json --insecure  
  1. After 1 minute all RAM in VM1 is consumed and Gitlab EE instance becomes completely unreachable.
PoC video

<redacted>

Impact

Gitlab EE becomes completely unavailable to legitimate users

Examples

(If the bug is project related, please create an example project and export it using the project export feature)

(If you are using an older version of GitLab, this will also help determine whether the bug has been fixed in a more recent version)

(If the bug can be reproduced on GitLab.com without violating the Rules of Engagement as outlined in the program policy, please provide the full path to the project.)

What is the current bug behavior?

Lack of size check before parsing Json payload (actually a JSON string) in below method:

https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/graphql/variables.rb#L23

 def ensure_hash(ambiguous_param)  
        case ambiguous_param  
        when String  
          if ambiguous_param.present?  
            ensure_hash(Gitlab::Json.parse(ambiguous_param))  
          else  
            {}  
          end  
        when Hash  
          ambiguous_param  
        ... // error handling codes  
      end  
What is the expected correct behavior?

Should check size before parsing or use a more memory efficient parser.

Relevant logs and/or screenshots

(Paste any relevant logs - please use code blocks (```) to format console output,
logs, and code as it's very hard to read otherwise.)

Output of checks

(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com)

Results of GitLab environment info
System information  
System:         Ubuntu 24.04  
Proxy:          no  
Current User:   git  
Using RVM:      no  
Ruby Version:   3.2.8  
Gem Version:    3.7.1  
Bundler Version:2.7.1  
Rake Version:   13.0.6  
Redis Version:  7.2.10  
Sidekiq Version:7.3.9  
Go Version:     unknown

GitLab information  
Version:        18.4.1-ee  
Revision:       270836848e7  
Directory:      /opt/gitlab/embedded/service/gitlab-rails  
DB Adapter:     PostgreSQL  
DB Version:     16.10  
URL:            http://<redacted>  
HTTP Clone URL: http://<redacted>/some-group/some-project.git  
SSH Clone URL:  git@<redacted>:some-group/some-project.git  
Elasticsearch:  no  
Geo:            no  
Using LDAP:     no  
Using Omniauth: yes  
Omniauth Providers: 

GitLab Shell  
Version:        14.45.2  
Repository storages:  
- default:      unix:/var/opt/gitlab/gitaly/gitaly.socket  
GitLab Shell path:              /opt/gitlab/embedded/service/gitlab-shell

Gitaly  
- default Address:      unix:/var/opt/gitlab/gitaly/gitaly.socket  
- default Version:      18.4.1  
- default Git Version:  2.50.1  

(For installations with omnibus-gitlab package run and paste the output of:
sudo gitlab-rake gitlab:env:info)

(For installations from source run and paste the output of:
sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production)

Impact

Gitlab EE becomes completely unavailable to legitimate users

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section:

3.

Edited by ADandy