Unprivileged access to Private Composer Package Repository packages
HackerOne report #1074148 by sjerdo
on 2021-01-08, assigned to @dcouture:
Report
Summary
Gitlab features a Package Registry which can be used for public and private repositories.
When a private repository publishes a Composer package (for private use), the package can be download by the URL, without any authentication. The only requirement is to obtain the dist download link from the composer.lock file
Steps to reproduce
- Create a new Private group
- Create a new Private project in the newly private group
- Add a default composer.json file to the project / create a composer package
{
"name": "sjerdo/private-project"
}
- Create a tag, e.g. 1.0.0
-
Create a personal access token with
api
access. - Publish the composer package using the API and the personal access token
- Create a blank composer project and install the package
- Obtain the dist url from the composer.lock file
- Download the zip at the dist url without setting authentication credentials. (eg. by using curl).
Impact
Private repositories (files) can be download by unauthorised users who can obtain the dist download URL or project ID, package name and git commit hash (eg. from a composer.lock file).
Examples
Repository: https://gitlab.com/my-private-group3/private-project
Published package: https://gitlab.com/my-private-group3/private-project/-/packages/958076
composer.json
{
"name": "sjerdo/security-test",
"authors": [
{
"name": "Sjoerd Wenker",
"email": "sjoerd@relisten.nl"
}
],
"require": {
"sjerdo/private-project": "^1.0"
},
"repositories": {
"gitlab.com/10584961": {
"type": "composer",
"url": "https://gitlab.com/api/v4/group/10584961/-/packages/composer/packages.json"
}
}
}
composer.lock:
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is [@]generated automatically"
],
"content-hash": "92f07e65c18a1a095eefd9baa735f09f",
"packages": [
{
"name": "sjerdo/private-project",
"version": "1.0.0",
"dist": {
"type": "zip",
"url": "https://gitlab.com/api/v4/projects/23533789/packages/composer/archives/sjerdo/private-project.zip?sha=76b4344d0ab1491807c8bace4aee112bf09e843d",
"reference": "76b4344d0ab1491807c8bace4aee112bf09e843d",
"shasum": ""
},
"type": "library"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "2.0.0"
}
dist download URL in composer.json: https://gitlab.com/api/v4/projects/23533789/packages/composer/archives/sjerdo/private-project.zip?sha=76b4344d0ab1491807c8bace4aee112bf09e843d
Alternative download URL which does require authentication: https://gitlab.com/api/v4/projects/23533789/repository/archive.zip?sha=76b4344d0ab1491807c8bace4aee112bf09e843d
What is the current bug behavior?
When I download the archive without authentication, download is not prohibited.
% curl 'https://gitlab.com/api/v4/projects/23533789/packages/composer/archives/sjerdo/private-project.zip?sha=76b4344d0ab1491807c8bace4aee112bf09e843d' --output response.zip
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 709 100 709 0 0 2037 0 --:--:-- --:--:-- --:--:-- 2037
% unzip archive.zip
creating: private-project-76b4344d0ab1491807c8bace4aee112bf09e843d-76b4344d0ab1491807c8bace4aee112bf09e843d/
extracting: private-project-76b4344d0ab1491807c8bace4aee112bf09e843d-76b4344d0ab1491807c8bace4aee112bf09e843d/composer.json
What is the expected correct behavior?
When I download the archive without authentication, download should be prohibited.
% curl 'https://gitlab.com/api/v4/projects/23533789/packages/composer/archives/sjerdo/private-project.zip?sha=76b4344d0ab1491807c8bace4aee112bf09e843d'
{"message":"404 Project Not Found"}
Relevant logs and/or screenshots
Publishing the package:
% curl --data tag=1.0.0 "https://__token__:<TOKEN>[@]gitlab.com/api/v4/projects/23533789/packages/composer"
{"message":"201 Created"}
Alternative URL does check authentication:
% curl 'https://gitlab.com/api/v4/projects/23533789/repository/archive.zip?sha=76b4344d0ab1491807c8bace4aee112bf09e843d'
{"message":"404 Project Not Found"}
Output of checks
This bug happens on GitLab.com
Results of GitLab environment info
n/a
Impact
Attacker can download private repository files without authorization.
How To Reproduce
Please add reproducibility information to this section: