{"id":19295,"date":"2022-12-09T09:43:04","date_gmt":"2022-12-09T08:43:04","guid":{"rendered":"https:\/\/herolab.usd.de\/?page_id=19295"},"modified":"2022-12-16T12:13:14","modified_gmt":"2022-12-16T11:13:14","slug":"usd-2022-0042","status":"publish","type":"page","link":"https:\/\/herolab.usd.de\/en\/security-advisories\/usd-2022-0042\/","title":{"rendered":"usd-2022-0042"},"content":{"rendered":"<p>[et_pb_section fb_built=\"1\" _builder_version=\"4.16\" _module_preset=\"default\" background_color=\"#2E353D\" custom_padding=\"||0px|||\" global_colors_info=\"{}\"][et_pb_row _builder_version=\"4.16\" _module_preset=\"default\" custom_padding=\"|0px||||\" hover_enabled=\"0\" global_colors_info=\"{}\" sticky_enabled=\"0\"][et_pb_column type=\"4_4\" _builder_version=\"4.16\" _module_preset=\"default\" global_colors_info=\"{}\"][et_pb_text _builder_version=\"4.19.2\" _module_preset=\"cc5ac6f4-ebbd-4b3f-bc92-4dfc1f15fe2c\" width=\"100%\" custom_margin=\"|2px|20px||false|false\" custom_padding=\"|8px||||\" hover_enabled=\"0\" global_colors_info=\"{}\" sticky_enabled=\"0\"]<\/p>\n<h1><\/h1>\n<h1>usd-2022-0042 | Dependecy Confusion in GitLab<\/h1>\n<h1><\/h1>\n<p><strong>Advisory ID<\/strong>: usd-2022-0042<br \/><strong>Product<\/strong>: GitLab<br \/><strong>Affected Version<\/strong>: GitLab Community Edition 15.2.2, probably others...<br \/><strong>Vulnerability Type<\/strong>: Uncontrolled Search Path Element (CWE-427)<br \/><strong>Security Risk<\/strong>: High<br \/><strong>Vendor URL<\/strong>: <a href=\"https:\/\/gitlab.com\" target=\"_blank\" rel=\"noopener\">https:\/\/gitlab.com<\/a><br \/><strong>Vendor acknowledged vulnerability<\/strong>: No<br \/><strong>Vendor Status<\/strong>: Not fixed<\/p>\n<h3>Affected Component(s)<\/h3>\n<p>The vulnerability affects the <em>Python Package Registry<\/em> that can be configured for distributing internal packages.<\/p>\n<h3>Description<\/h3>\n<p><em>pip<\/em> is probably the most popular <em>Python<\/em> package manager and can be used to install packages from the publicly<br \/>available <em>Python Package Index<\/em> (<em>PyPi<\/em>) at <a href=\"https:\/\/pypi.org\" target=\"_blank\" rel=\"noopener\">pypi.org<\/a> or form internal package repositories. In the beginning of 2021,<br \/>a vulnerability type called <em>Dependency Confusion<\/em> attracted some attention in the information security scene. Several<br \/>high profiled companies were identified to accidentally load internal dependencies from the public available index<br \/>at <em>PyPi<\/em>. This could have allowed any <em>PyPi<\/em> user to register packages with the accidentally requested names<br \/>and to achieve remote code execution on the affected systems.<\/p>\n<p>The underlying reason for the vulnerability was the usage of the <strong>--extra-index-url<\/strong> parameter when installing packages<br \/>via <em>pip<\/em>. This parameter adds additional packages sources where <em>pip<\/em> checks for the desired installation candidate. That<br \/>being said, the publicly available index at <em>PyPi<\/em> remains within the sources and will be used if the requested version<br \/>of the desired package can be found. In case of no version was specified, <em>pip<\/em> installs the most recent version it finds<br \/>among all configured repositories.<\/p>\n<p>After the <em>Dependency Confusion<\/em> got publicly known, the general recommendation was to use <strong>--index-url<\/strong> instead of<br \/><strong>--extra-index-url<\/strong>, which replaces <a href=\"https:\/\/pypi.org\" target=\"_blank\" rel=\"noopener\">pypi.org<\/a> as the default package registry. <em>GitLab<\/em>, however, still advises it's<br \/>users to use <strong>--extra-index-url<\/strong> within the web overview of a projects package registry. Therefore, users that are not<br \/>aware of <em>Dependency Confusion<\/em>, might accidentally install internal <em>GitLab<\/em> packages from the publicly available index<br \/>at <em>PyPi<\/em>.<\/p>\n<p>Moreover, with version <strong>14.2<\/strong>, <em>GitLab<\/em> made even usage of <strong>--index-url<\/strong> not fail save. According to the<br \/><a href=\"https:\/\/docs.gitlab.com\/ee\/user\/admin_area\/settings\/continuous_integration.html#pypi-forwarding\" target=\"_blank\" rel=\"noopener\">documentation<\/a>:<\/p>\n<blockquote>\n<p>In GitLab 14.2 and later, when a PyPI package is not found in the Package Registry, the request is forwarded to pypi.org.<\/p>\n<\/blockquote>\n<p>This configuration can lead to dangerous side effects when installing internal packages with other internal dependencies<br \/>or when using <strong>--index-url<\/strong> with another internal URL in the <strong>--extra-index-url<\/strong> parameter. <em>GitLab<\/em> defines package registries on the project and group level. If package dependecies cross these project or group boundaries, dependecy confusion is possible.<\/p>\n<h3>Proof of Concept<\/h3>\n<p>First, we create a simple python project <strong>usd-example-package<\/strong> and make it available over the projects package<br \/>registry within <em>GitLab<\/em>. Viewing the webpage of the newly created package, it shows the following installation command:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/herolab.usd.de\/wp-content\/uploads\/sites\/9\/2022\/10\/usd-2022-0042.png\" width=\"818\" height=\"379\" alt=\"\" class=\"wp-image-18847 alignnone size-full\" srcset=\"https:\/\/herolab.usd.de\/wp-content\/uploads\/sites\/9\/2022\/10\/usd-2022-0042.png 818w, https:\/\/herolab.usd.de\/wp-content\/uploads\/sites\/9\/2022\/10\/usd-2022-0042-480x222.png 480w\" sizes=\"(min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) 818px, 100vw\" \/><\/p>\n<p>As one can see, the suggested install command uses the <strong>--extra-index-url<\/strong> by default, which makes it vulnerable to<br \/>dependency confusion.<\/p>\n<p>Now lets go one step further. Within our example package, we add an internal dependency <strong>usd-example-dependecy<\/strong>. This dependency is contained within another project and we add <strong>--extra-index-url<\/strong> to include this within the repository sources.<br \/>The installation command now looks like this:<\/p>\n<div class=\"codehilite\" style=\"background: #263238;color: #eff\">\n<pre style=\"line-height: 125%\"><span style=\"background: #263238\"><\/span><span class=\"gp\" style=\"background: #263238;color: #ffcb6b\">$ <\/span>pip install usd-example-project --index-url <span class=\"o\" style=\"background: #263238;color: #89ddff\">[<\/span>https:\/\/gitlab.example.com\/api\/v4\/projects\/10\/packages\/pypi\/simple<span class=\"o\" style=\"background: #263238;color: #89ddff\">]()<\/span> --extra-index-url <span class=\"o\" style=\"background: #263238;color: #89ddff\">[<\/span>https:\/\/gitlab.example.com\/api\/v4\/projects\/11\/packages\/pypi\/simple<span class=\"o\" style=\"background: #263238;color: #89ddff\">]()<\/span><\/pre>\n<\/div>\n<p>Since <strong>--index-url<\/strong> was used, <a href=\"https:\/\/pypi.org\" target=\"_blank\" rel=\"noopener\">pypi.org<\/a> should not be considered when searching for packages and the installation command should be safe, right? Well, after launching the command, <em>pip<\/em> first loads <strong>usd-example-project<\/strong> from the URL specified as <strong>--index-url<\/strong>:<\/p>\n<div class=\"codehilite\" style=\"background: #263238;color: #eff\">\n<pre style=\"line-height: 125%\"><span style=\"background: #263238\"><\/span><span class=\"nf\" style=\"background: #263238;color: #82aaff\">GET<\/span> <span class=\"nn\" style=\"background: #263238;color: #ffcb6b\">\/api\/v4\/projects\/10\/packages\/pypi\/simple\/usd-example-dependecy\/<\/span> <span class=\"kr\" style=\"background: #263238;color: #bb80b3\">HTTP<\/span><span class=\"o\" style=\"background: #263238;color: #89ddff\">\/<\/span><span class=\"m\" style=\"background: #263238;color: #f78c6c\">1.1<\/span>\n<span class=\"na\" style=\"background: #263238;color: #bb80b3\">Host<\/span><span class=\"o\" style=\"background: #263238;color: #89ddff\">:<\/span> <span class=\"l\" style=\"background: #263238;color: #c3e88d\">gitlab.example.com<\/span><\/pre>\n<\/div>\n<p>Afterwards, the <strong>--extra-index-url<\/strong> is checked as described above, but since it belongs to our internal trusted <em>GitLab<\/em> instance, this should be fine:<\/p>\n<div class=\"codehilite\" style=\"background: #263238;color: #eff\">\n<pre style=\"line-height: 125%\"><span style=\"background: #263238\"><\/span><span class=\"nf\" style=\"background: #263238;color: #82aaff\">GET<\/span> <span class=\"nn\" style=\"background: #263238;color: #ffcb6b\">\/api\/v4\/projects\/11\/packages\/pypi\/simple\/usd-example-project\/<\/span> <span class=\"kr\" style=\"background: #263238;color: #bb80b3\">HTTP<\/span><span class=\"o\" style=\"background: #263238;color: #89ddff\">\/<\/span><span class=\"m\" style=\"background: #263238;color: #f78c6c\">1.1<\/span>\n<span class=\"na\" style=\"background: #263238;color: #bb80b3\">Host<\/span><span class=\"o\" style=\"background: #263238;color: #89ddff\">:<\/span> <span class=\"l\" style=\"background: #263238;color: #c3e88d\">gitlab.example.com<\/span><\/pre>\n<\/div>\n<p>However, since <strong>usd-example-package<\/strong> is only distributed within the project with ID 10, the registry for project ID 11 will not find the requested package and forward the request to <em>PyPi<\/em>:<\/p>\n<div class=\"codehilite\" style=\"background: #263238;color: #eff\">\n<pre style=\"line-height: 125%\"><span style=\"background: #263238\"><\/span><span class=\"kr\" style=\"background: #263238;color: #bb80b3\">HTTP<\/span><span class=\"o\" style=\"background: #263238;color: #89ddff\">\/<\/span><span class=\"m\" style=\"background: #263238;color: #f78c6c\">1.1<\/span> <span class=\"m\" style=\"background: #263238;color: #f78c6c\">302<\/span> <span class=\"ne\" style=\"background: #263238;color: #ffcb6b\">Found<\/span>\n<span class=\"na\" style=\"background: #263238;color: #bb80b3\">Location<\/span><span class=\"o\" style=\"background: #263238;color: #89ddff\">:<\/span> <span class=\"l\" style=\"background: #263238;color: #c3e88d\">[https:\/\/pypi.org\/simple\/usd-example-project\/]()<\/span><\/pre>\n<\/div>\n<p>Now, although we used <strong>--index-url<\/strong>, we are again vulnerable to dependency confusion.<\/p>\n<h3>Fix<\/h3>\n<p>The reported issue should be fixed by making the following adjustments:<\/p>\n<ol>\n<li>The insecure installation command suggested by the repository webpages should be replaced. Instead of <strong>--extra-index-url<\/strong>, the <strong>--index-url<\/strong> command line option should be chosen.<\/li>\n<li>Forwarding of requests for unknown packages to <a href=\"https:\/\/pypi.org\" target=\"_blank\" rel=\"noopener\">pypi.org<\/a> should be disabled by default. This setting can have dangerous side effects and should not be enabled by default. Administrators that understand the consequences could still enable the feature for their instance.<\/li>\n<\/ol>\n<p>We are aware that automatic forwarding of unknown packages to <em>PyPi<\/em> increases the usability of internal package registries quite a lot. Installation of internal tools and dependencies usually also requires installation of packages that are available on <em>PyPi<\/em>. Restricting the index to an internal repository makes automatic installation of these external dependencies fail, which creates some additional installation effort.<br \/>That being said, the accidental installation of potentially malicious software from a public package registry represents a high security risk for organisations and should be classified as more important as usability.<\/p>\n<p>Another possible solution would be to only allow forwarding requests to <em>PyPi<\/em> for packages that are not available within the whole internal <em>GitLab<\/em> instance.<\/p>\n<h3>References<\/h3>\n<ul>\n<li><a>https:\/\/medium.com\/@alex.birsan\/dependency-confusion-4a5d60fec610<\/a><\/li>\n<li><a>https:\/\/docs.gitlab.com\/ee\/user\/packages\/pypi_repository\/<\/a><\/li>\n<li><a>https:\/\/docs.gitlab.com\/ee\/user\/admin_area\/settings\/continuous_integration.html#pypi-forwarding<\/a><\/li>\n<li>GitLab Issue: <a href=\"https:\/\/gitlab.com\/gitlab-org\/gitlab\/-\/issues\/384253\" target=\"_blank\" rel=\"noopener\">https:\/\/gitlab.com\/gitlab-org\/gitlab\/-\/issues\/384253<\/a><\/li>\n<li>GitLab Merge Request: <a href=\"https:\/\/gitlab.com\/gitlab-org\/gitlab\/-\/merge_requests\/105662\" target=\"_blank\" rel=\"noopener\">https:\/\/gitlab.com\/gitlab-org\/gitlab\/-\/merge_requests\/105662<\/a><\/li>\n<\/ul>\n<h3>Timeline<\/h3>\n<ul>\n<li><strong>2022-08-24<\/strong>: Vulnerability identified by Tobias Neitzel<\/li>\n<li><strong>2022-08-26<\/strong>: First contact request via Hackerone <a>https:\/\/hackerone.com\/reports\/1681275<\/a><\/li>\n<li><strong>2022-08-27<\/strong>: HackerOne Triage Team has received the advisory<\/li>\n<li><strong>2022-09-15<\/strong>: Responsible Disclosure Team answers follow-up questions about the submitted HackerOne report<\/li>\n<li><strong>2022-09-19<\/strong>: HackerOne triage team forwards report internally to GitLab team<\/li>\n<li><strong>2022-09-24<\/strong>: HackerOne report is closed with the status \"Informational\"<\/li>\n<li><strong>2022-11-21<\/strong>: HackerOne report disclosure request was granted<\/li>\n<li><strong>2022-12-01<\/strong>: usd Responsible Disclosure team submits Issue &amp; Merge Request via GitLab<\/li>\n<li><strong>2022-12-09<\/strong>: The advisory is published<\/li>\n<\/ul>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h3>Credits<\/h3>\n<p>This security vulnerability was identified by Tobias Neitzel of usd AG.<\/p>\n<p>[\/et_pb_text][\/et_pb_column][\/et_pb_row][\/et_pb_section]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>usd-2022-0042 | Dependecy Confusion in GitLab Advisory ID: usd-2022-0042Product: GitLabAffected Version: GitLab Community Edition 15.2.2, probably others...Vulnerability Type: Uncontrolled Search Path Element (CWE-427)Security Risk: HighVendor URL: https:\/\/gitlab.comVendor acknowledged vulnerability: NoVendor Status: Not fixed Affected Component(s) The vulnerability affects the Python Package Registry that can be configured for distributing internal packages. Description pip is probably the [&hellip;]<\/p>\n","protected":false},"author":109,"featured_media":17032,"parent":16124,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_et_pb_use_builder":"on","_et_pb_old_content":"","_et_gb_content_width":"","inline_featured_image":false,"footnotes":""},"class_list":["post-19295","page","type-page","status-publish","has-post-thumbnail","hentry"],"_links":{"self":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages\/19295","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/users\/109"}],"replies":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/comments?post=19295"}],"version-history":[{"count":0,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages\/19295\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/pages\/16124"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/media\/17032"}],"wp:attachment":[{"href":"https:\/\/herolab.usd.de\/en\/wp-json\/wp\/v2\/media?parent=19295"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}