Disclosure of private repository names

HackerOne report #636952 by mclaren650sspider on 2019-07-06, assigned to estrike:

Summary

This bug exists due to this line https://gitlab.com/gitlab-org/gitlab-ce/blob/108c3cf16bed5733ffae086fb62c226961356560/app/controllers/concerns/lfs_request.rb#L95
When an user submits request to upload file to LFS, it is first checked that LFS is enabled on the given repository. However, if the repository does not exist, this line causes exception, resulting 500 Internal Server Error to be shown to the client. If the repository exists, no exception is raised and this endpoint returns 404 Not Found.

Steps to reproduce

  1. Use any GitLab account. This account is our target, let's say that its username is target. Create private repository with this account. Let's say that the URL of the repository is https://gitlab.com/target/secretrepo
  2. Use another GitLab account, let's say that its username is attacker. Add SSH key to this account.
  3. Create new repository with attacker account (does not matter if it is private or not), let's say that this repo is located at https://gitlab.com/attacker/randomrepo. This is necessary to obtain the authorization token in the next step.
  4. With previously added SSH key, execute the command ssh git@gitlab.com -x "git-lfs-authenticate attacker/randomrepo.git upload".
    Replace attacker/randomrepo accordingly.
  5. The executed command should produce JSON output. Copy the value of Authorization header.
  6. Replace AUTHORIZATION_TOKEN in the script below with the token obtained in step 5. Replace target/secretrepo according to your target's username and private repository name.
    Execute the script.
curl -i -X POST \  
	-H 'Authorization: AUTHORIZATION_TOKEN' \  
	-H 'Content-Type: application/json' \  
	-d '{"operation":"upload","transfers":["basic"],"ref":{"name":"refs/heads/master"},"objects":[{"oid":"f6eae78dc35680d85254d68750fb702e464097ab3c2e4c4daf811dd973d5ac60","size":9}]}' \  
	'https://gitlab.com/target/secretrepo.git/info/lfs/objects/batch'  
  1. Observe that the script returns 404.
  2. Now replace the secretrepo in the script with any other repository name. Execute the script again and observe that it produces error 500 instead of 404.

What is the current bug behavior?

The endpoint returns different error depending on whether or not the repository exists.

What is the expected correct behavior?

The error that the endpoint produces should always the same, regardless of whether repository exists or not.

Output of checks

This bug happens on GitLab.com, but can be reproduced in CE/EE as well.

Impact

This vulnerability can be used to know whether user has private repository with given name or not. Attacker can utilize this vulnerability to enumerate the list of private repositories that one user or organization has. Names of private repositories could contain sensitive information or business secrets.

Edited Nov 04, 2019 by GitLab SecurityBot
Assignee Loading
Time tracking Loading