Skip to content

Bypassing Code Owners branch protection rule in GitLab

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 #1898054 by inspector-ambitious on 2023-03-09, assigned to @cmaxim:

Report | Attachments | How To Reproduce

Report

Summary

I believe I discovered a vulnerability that could potentially allow an attacker with Developer Role access to a repository to circumvent Code Owners approval branch protection when submitting merge requests.

This could be accomplished by creating a tag with the same name as the protected branch, which would render the Code Owners approval rule ineffective.

The following is extracted from this documentation.

A symbolic ref name. E.g. master typically means the commit object referenced by refs/heads/master. If you happen to have both heads/master and tags/master, you can explicitly say heads/master to tell Git which one you mean. When ambiguous, a <refname> is disambiguated by taking the first match in the following rules:

If $GIT_DIR/<refname> exists, that is what you mean (this is usually useful only for HEAD, FETCH_HEAD, ORIG_HEAD, MERGE_HEAD and CHERRY_PICK_HEAD);

  • otherwise, refs/<refname> if it exists;

  • otherwise, refs/tags/<refname> if it exists;

  • otherwise, refs/heads/<refname> if it exists;

  • otherwise, refs/remotes/<refname> if it exists;

  • otherwise, refs/remotes/<refname>/HEAD if it exists.

Consequently by abusing git ambiguous ref name, an attacker could merge the request without the required approval, because a CODEOWNERS file inside a tag reference will take precedence over the one in the branch assuming both tag and branch have the same name.

Steps to reproduce

To reproduce this vulnerability we will use one repository and 2 accounts

  • a maintainer/victim: root
  • a developer/attacker: inspector
Step 1: Repository setup (victim context)
  1. Create a blank private repository with a README.

  2. Add a CODEOWNERS file with the following content

* [@]root  

image.png

  1. Create another branch called devel based on main

image.png

Please note that since we can't create tags that matches the default branch, this attack can only target a non default branch (hence we will run it against devel)

  1. Go to Settings > Repository and add devel as a protected branch.

image.png

Allowed to merge: Developers + Maintainers
Allowed to push and merge: Maintainers
Allowed to force push: Disabled
Code owner approval: Enabled

  1. Go to Setting > Merge Requests and at the bottom of the page tick the box Prevent editing approval rules in merge requests and save the changes.

image.png

Please note that at this stage the branch devel is protected, because no Developer can merge a Merge Request or push to it without prior approval from [@]root as defined in the CODEOWNERS file.

  1. Go to Project Information > Members and add [@]inspector as a member with the role Developer.

image.png

Step 2: The attack (attacker context)
  1. Clone the repository and create push the malicious tag.
git clone git@gitlab.server:gitlab-instance-xxxx/codeowners_bypass.git  
cd codeowners_bypass  
git fetch origin # optional  
git checkout origin/devel -b devel_tag  
rm CODEOWNERS  
git add CODEOWNERS  
git commit -m "attack"  
git push origin devel_tag:refs/tags/devel  

At this stage the Code Owners approval rules are disabled.

  1. Prepare a branch with malicious content.
git checkout origin/devel -b hack  
echo 1 > malicious_file  
git add malicious_file  
git commit -m "add malicious_file"  
git push origin hack  
  1. Create a Merge Request from hack to devel and merge it.

image.png

image.png

  1. Delete the tag to cover your track
git push origin -d refs/tags/devel  
  1. Finally go to the devel branch.

image.png

The malicious_file is there, the devel branch integrity has been compromised !

What is the current bug behavior?

The merge request can be merged since approval becomes optional.

image.png

What is the expected correct behavior?

The merge should be blocked since it requires approval from Code Owners.

image.png

Output of checks

While tested on a local instance (15.9.2 ) only, it is likely this vulnerability affects GitLab.com as well.

Impact

This can potentially compromise the integrity of the source code hosted on the repository and/or allow the attacker to execute malicious code on the affected systems (developer machines, stealing Gitlab CI secrets, supply chain attack etc...).
Please also note that the attack does not require any user interaction from the maintainer of the repository to be carried out.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section: