Skip to content

Add outbound allowlist to allowed URIs for SSRF filter

Context

https://gitlab.com/gitlab-org/security/gitlab/-/merge_requests/4137+ introduced the SSRF filtering for the packages dependency proxy.

https://gitlab.com/gitlab-com/request-for-help/-/issues/2233#note_2439576170 revealed that, when the private host is used to fetch the dependencies, such requests won't be allowed by SSRF filter in the workhorse.

What does this MR do and why?

Add outbound_local_requests_whitelist from the settings to the list of allowed endpoints for SSRF filter for the packages dependency proxy and virtual registries.

Since the outbound_local_requests_whitelist is a user input in the free form. I've chosen to rename allowed_uris to allowed_endpoints since the later better covers the various formats we're supporting (URLs, host combinations, and plain hostnames).

References

https://gitlab.com/gitlab-org/gitlab/-/issues/534288+s

Screenshots or screen recordings

No.

How to set up and validate locally

Packages dependency proxy

  1. To simplify the verification allow local IP addresses in the dependency proxy settings and not allow local IP addressed for SSRF filtering in the workhorse.
diff
diff --git a/ee/app/models/dependency_proxy/packages/setting.rb b/ee/app/models/dependency_proxy/packages/setting.rb
index 7b92e386e4b3..cbbc1877f8d7 100644
--- a/ee/app/models/dependency_proxy/packages/setting.rb
+++ b/ee/app/models/dependency_proxy/packages/setting.rb
@@ -40,7 +40,7 @@ class Setting < ApplicationRecord
 
       # maven
       validates :maven_external_registry_url,
-        addressable_url: { allow_localhost: false, allow_local_network: false },
+        addressable_url: { allow_localhost: true, allow_local_network: true },
         if: :maven_external_registry_url?
       validates :maven_external_registry_username, presence: true, if: :maven_external_registry_password?
       validates :maven_external_registry_password, presence: true, if: :maven_external_registry_username?
diff --git a/ee/lib/api/concerns/dependency_proxy/packages_helpers.rb b/ee/lib/api/concerns/dependency_proxy/packages_helpers.rb
index d322bf7abe9d..23193557eaf2 100644
--- a/ee/lib/api/concerns/dependency_proxy/packages_helpers.rb
+++ b/ee/lib/api/concerns/dependency_proxy/packages_helpers.rb
@@ -199,7 +199,7 @@ def require_non_web_browser!
             end
 
             def allow_localhost
-              Gitlab.dev_or_test_env? || Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
+              false # Gitlab.dev_or_test_env? || Gitlab::CurrentSettings.allow_local_requests_from_web_hooks_and_services?
             end
 
             def allowed_uris
  1. Prepare the third party server

    $ mkdir simple-server
    $ cd simple-server
    $ touch Gemfile
    $ touch server.rb
    # Gemfile
    source 'https://rubygems.org'
    gem 'rackup', '~> 2.1'
    gem 'sinatra', '~> 4.0'
    
    # server.rb
    require 'sinatra'
    
    get '/foo/1/bar' do
      'Hello world!'
    end
    $ bundle install
    $ ruby server.rb

    Copy the server URL with port

  2. Enable maven dependency proxy for the chosen project

    Visit the packages and registries settings of your project http://gdk.test:3000/gitlab-org/gitlab-test/-/settings/packages_and_registries 
    Use the URL of the third party server as a URL for the maven dependency proxy and save the configuration.
  3. Add the third party server IP to the list of allowed outbound IPs

    Visit http://gdk.test:3000/admin/application_settings/network#js-outbound-settings
    Add the IP to the list of allowed outbound IPs.
  4. Test maven dependency proxy

    $ curl -v http://<maintainer-username>:<maintainer-pat>@gdk.test:3000/api/v4/projects/<project-id>/dependency_proxy/packages/maven/foo/1/bar

    The response is expected to be 200 and the workhorse logs will have the corresponding similar entry:

    {"backend_id":"rails","content_type":"text/html;charset=utf-8","correlation_id":"01JSH9A272FSKRWGX26RR7QJ2R","duration_ms":1377,"host":"gdk.test:3000","level":"info","method":"GET","msg":"access","proto":"HTTP/1.1","read_bytes":232,"referrer":"","remote_addr":"172.16.123.1:61029","remote_ip":"172.16.123.1","route":"^/api/","route_id":"api","status":200,"system":"http","time":"2025-04-23T14:17:37+02:00","ttfb_ms":1048,"uri":"/api/v4/projects/1/dependency_proxy/packages/maven/foo/1/bar","user_agent":"curl/8.11.1","written_bytes":12}

    Now, remove the third party server IP from the list of allowed outbound IPs and repeat the request.

    The server should respond with the error.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #534288

Edited by Dzmitry (Dima) Meshcharakou

Merge request reports

Loading