Spoofing of the contents of a protected branch by creating a tag with the same name as the protected branch

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 #2121310 by ricardobrito on 2023-08-23, assigned to GitLab Team:

Report | Attachments | How To Reproduce

Report

Hi team,

Summary

I have found that it is possible for a user with developer role to spoof the contents of a protected branch by creating a tag with the same name as the protected branch.

Pre-requisites
  1. An instance admin account.
  2. A normal user - User A
  3. A normal user - User B
  4. Create an access token for user A
  5. Create an access token for user B
Steps to reproduce
  1. As the instance admin, create a private group called admin-group

  2. As the instance admin, create a project (private) called admin-project inside the group created in step 1.

  3. As the instance admin (now group owner), invite User A and User B as developers.

  4. As the group owner, create a file called .gitlab-ci.yml inside the project with the following content:

build-job:  
  stage: build  
  script:  
    - echo "Hello, ADMIN"  
  1. As the group owner, edit the .gitlab-ci.yml file using the gitlab ide:

image.png

change the contents to:

build-job:  
  stage: build  
  script:  
    - echo "Hello, ADMIN FROM BRANCH"  

Commit the changes to a new branch called devel

  1. Still as the owner, go to the repository settings -> expand the Protected branches section, select the devel branch and set the following rules:

Allowed to merge: maintainrers
Allowed to push and merge: maintainrers

Press the protect button

  1. As user A, clone the project using the gitlab token, with the following command:

git clone http://USER-A:glpat-_USER-A-TOKEN@YOUR-GITLAB-INSTANCE/admin-group/admin-project

Then run the following commands:

cd admin-project
git checkout origin/devel -b devel_tag

  1. Still as User A, edit the file .gitlab-ci.yml with the following contents (locally):
build-job:  
  stage: build  
  script:  
    - echo "Hello, USER A"  

and save the changes.

  1. Still as User A, run the following commands:

git add -A
git commit -m "attack"
git push origin devel_tag:refs/tags/devel

This will push the changes to a new tag called devel.

  1. As User B, go to http://YOUR-GITLAB-INSTANCE/admin-group/admin-project, and click on the branches button (which should show 2, as highlighted below):

Screenshot_2023-08-23_at_9.45.02_PM.png

Click on the highlighted section in the image above and it will take you to http://127.0.0.1:3000/admin-group/admin-project/-/branches, where you will see 2 branches: main and devel (which is the protected branch that neither USER A or USER B have permission to push code to).

image.png

  1. As user B, click on the devel branch and you should see that it shows the contents that were commited and pushed by User A instead of the original protected devel branch. (** Impact: The contents of the protected branch have been spoofed by a user who does not have push rights into the branch, allowing him to deliver fake content to other users**)

image.png

If User B clicks on the .gitlab-ci.yml file, he will see the contents pushed by User A:

image.png

  1. Still as user B, clone the project locally using the gitlab token and cd into the directory and run the following command:
    git checkout devel

Then open the .gitlab-ci.yml file and you will see that it contains the contents pushed by User A, instead of the original contents of the protected branch.

Impact

The impact here is two-fold:

  1. After User A makes changes to the protected branch and pushes the changes into a tag with the same name as the protected branch (say devel), whoever visits the branches page in the UI of the project and clicks on the devel branch, will see the changes pushed by user A instead of seeing the contents of the original protected branch.

  2. If another user clones the project and checks out the devel branch, he will be checking out the contents of the tag pushed by User A instead of the original protected branch.

Impact

The impact here is two-fold:

  1. After User A makes changes to the protected branch and pushes the changes into a tag with the same name as the protected branch (say devel), whoever visits the branches page in the UI of the project and clicks on the devel branch, will see the changes pushed by user A instead of seeing the contents of the original protected branch.

  2. If another user clones the project and checks out the devel branch, he will be checking out the contents of the tag pushed by User A instead of the original protected branch.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section: