DoS in Markdown preview caused by a bug in RepositoryLinkFilter
HackerOne report #3517644 by maksyche on 2026-01-20, imported by @greg:
Report | Attachments | How To Reproduce
HackerOne Analyst Summary
Summary of the issue
The researcher found DoS when opening Markdown file with the large number of ../ prefixes.
Steps to reproduce
- As the attacker, use SSH port forwarding to connect victim's GDK on attacker's localhost port 3000
Note: By default, GDK is not accessible publicly. This step is used to connect target GDK from the attacker's machine, and it is not required in the real attack.
- As the attacker, sign in attacker's account on GDK, with latest commit
18.9.0-pre 39aebb0dbcd-> Create a public project -> In the project, upload dos.md:
- As the attacker, run following command to start attack -> Replace
ATTACKER_GROUP/ATTACKER_PROJECTwith attacker's group and project name:
while true; do curl -s -o /dev/null -w "%{time_total}s\n" "http://localhost:3000/ATTACKER_GROUP/ATTACKER_PROJECT/-/blob/main/dos.md?format=json&viewer=rich" & sleep 1; done
- (Optional) As the victim, check htop on GDK host machine. CPU or memory is not fully consumed:
- As the victim, try to access GitLab instance. You can see victim is not able to access it:
Impact statement
Malicious user can prevent other user from accessing the target GitLab instance.
If you have any questions or concerns about this report, feel free to assign it to H1 Triage via the action picker with a comment indicating your request.
Original Report
Hi
Summary
Current implementation of build_relative_path in repository_link_filter.rb removes the ../ prefix and shifts the whole string, which is a CPU-heavy operation. An attacker can create a small publicly accessible.md file with a huge number of these prefixes. A very small number of unauthenticated requests to read this file cause CPU overload and the instance becomes completely unusable.
Steps to reproduce
-
Create a 1k-users virtual machine (I used AWS
c5.2xlarge). -
Install Gitlab CE (I used Ubuntu). During the installation, I used the
http://gitlab.example.comEXTERNAL_URLwithouthttpsand updated local/etc/hoststo link the IP address of the machine and this domain. - Log into Gitlab and create a public
root/dosproject with just a README file. - Upload the
file.
- Observe that when you try to preview the file, the request either fails or takes 20+ seconds to load.
- Since the project is public, you can query this file unauthenticated. Run this command from your machine to request the file every second (that's ~5% of the expected traffic for this instance type. I managed to make the instance unusable even with 1-2% of the traffic):
while true; do curl -s -o /dev/null -w "%{time_total}s\n" "http://gitlab.example.com/root/dos/-/blob/main/dos.md?format=json&viewer=rich" & sleep 1; done
- Observe that Gitlab becomes completely unusable within seconds.
Impact
A small number of unauthenticated requests can make a Gitlab instance completely unusable within seconds.
What is the current bug behavior?
The server eats all the CPU resources within seconds even with less than 5% of traffic (I tested and even 1-2% of traffic can be enough).
What is the expected correct behavior?
Prefix calculation must be optimized. Something like this:
pos = 0
while path[pos, 3] == '../'
parts.pop
pos += 3
end
path = path[pos..] || ''
Relevant logs and/or screenshots
Here's the video PoC:
Results of GitLab environment info
sudo gitlab-rake gitlab:env:info
System information
System: Ubuntu 24.04
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.11
Sidekiq Version:7.3.9
Go Version: unknown
GitLab information
Version: 18.8.1
Revision: d0311b03573
Directory: /opt/gitlab/embedded/service/gitlab-rails
DB Adapter: PostgreSQL
DB Version: 16.11
URL: http://gitlab.example.com
HTTP Clone URL: http://gitlab.example.com/some-group/some-project.git
SSH Clone URL: git@gitlab.example.com:some-group/some-project.git
Using LDAP: no
Using Omniauth: yes
Omniauth Providers:
GitLab Shell
Version: 14.45.5
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.8.1
- default Git Version: 2.52.GIT
Impact
A small number of unauthenticated requests can make a Gitlab instance completely unusable within seconds.
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
How To Reproduce
Please add reproducibility information to this section:


