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
- 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 ishttps://gitlab.com/target/secretrepo
- Use another GitLab account, let's say that its username is
attacker
. Add SSH key to this account. - Create new repository with
attacker
account (does not matter if it is private or not), let's say that this repo is located athttps://gitlab.com/attacker/randomrepo
. This is necessary to obtain the authorization token in the next step. - With previously added SSH key, execute the command
ssh git@gitlab.com -x "git-lfs-authenticate attacker/randomrepo.git upload"
.
Replaceattacker/randomrepo
accordingly. - The executed command should produce JSON output. Copy the value of
Authorization
header. - Replace
AUTHORIZATION_TOKEN
in the script below with the token obtained in step 5. Replacetarget/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'
- Observe that the script returns 404.
- 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.