Skip to content

Smuggling content in MR with refs/replace 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 #1938185 by inspector-ambitious on 2023-04-07, assigned to @ottilia_westerlund:

Report | Attachments | How To Reproduce

Report

Summary

In Git, the refs/replace namespace is used to create a temporary reference that points to a commit object, allowing for the replacement or overwriting of an existing commit with a new one.
When a new commit object is created in Git, it is assigned a unique SHA-1 hash that identifies it in the repository's history.

However, an attacker with the Developer role in a repository can push a replacement reference in the refs/replace namespace, which would replace an existing commit with a malicious one. And if the head commit of a MR is replaced with a malicious one, we will get a situation where the MR will show the original commit but what would be merged will be the malicious one instead. Therefore this would allow an attacker to inject malicious code in the protected branch.
You can find a documentation on git replace here.

Steps to reproduce

To reproduce this vulnerability we will need 2 users:

  • victim01 the victim and repository owner.
  • inspector-ambitious the attacker with Developer access.

Step 1: Setup repository (in victim context victim01)

  1. Create an empty (no README) private project called replace

  2. Add one empty file called a. (we need at least one commit)

image.png

  1. Go to Settings > Repository > Protected Branches and check that main branch is protected

image.png

It should be the default setup. Only maintainers can merge or push to this branch.

  1. Got to Project information > Members and invite inspector-ambitious with the role Developer

image.png

Step 2: Attack preparation (in attacker context inspector-ambitious)

** It is extremely important to respect the order of operations here **

  1. Create a new branch from main called b for example
  2. Add a new empty file called bin the branch b

image.png

  1. Create a branch called c from main with an empty file called c

image.png

  1. Clone the repository and run git ls-remote in the terminal

image.png

  1. Now push a refs/replace reference to replace commit from b with c

in our case based on previous output of ls-remote

image.png

running git ls-remote again we get

image.png

  1. Create a MR from b to main.

image.png

image.png

image.png

As you can see only the file b should be added when this PR is merged.

Step 3: main branch is compromised (in victim context victim01)

  1. Go to the pull request and merge it.

image.png

  1. Go to the main branch

image.png

You can see the file c from c got merged !

The commit history looks correct.

image.png

However if we look at the merge commit we see that c was added instead of b

image.png

Output of checks

This bug happens on GitLab.com, I tried to reproduce it on a local instance but somehow it didn't work out...

Impact

A collaborator can bypass branch protection and smuggle malicious content in a merge request, which could potentially introduce security vulnerabilities or other types of defects into the codebase, compromising the integrity and security of the repository. This could result in sensitive data being leaked, unauthorized access to resources, or even complete system compromise.

Attachments

Warning: Attachments received through HackerOne, please exercise caution!

How To Reproduce

Please add reproducibility information to this section: