Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

FeedsContactPrivacy© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
gitlab-gitea-import-ssrf — GitLab - High - Gitea HTTPS import SSRF - UrlBlocker pin drop | Kitploit
Tools/GitHubGitHub/abraxas/gitlab-gitea-import-ssrf
Vulnerability AnalysisExploitationWeb Application ExploitationWeb SecurityPenetration TestingLabs & Practice
GitHubabraxas/gitlab-gitea-import-ssrf

gitlab-gitea-import-ssrf

GitLab - High - Gitea HTTPS import SSRF - UrlBlocker pin drop

View Repository
15 days agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

Abraxas Labs - gitlab-gitea-import-ssrf

abraxaslabs.tech  ·  github.com/abraxas  ·  @abraxas_null  ·  [email protected]  ·  gitlab-gitea-import-ssrf

gitlab-gitea-import-ssrf

GitLab CE 19.4.1 - GitLab Inc.

Gitea import calls UrlBlocker.validate! once, then for https throws away the IP-pinned URI and hands Faraday the original hostname. Octokit UrlValidation validates again and does not rewrite env[:url]. Rebind the name between those lookups and GitLab GETs loopback as if it were Gitea. The repo-list JSON comes back on GET /import/gitea/status.json. HTTP imports keep the pin. Direct https://127.0.0.1 is blocked.

A signed-in user who can open Gitea import on their personal namespace can make GitLab fetch a host they rebind to loopback, and they get the body.

IDno CVE yet
CWECWE-918, CWE-367
CVSSHigh: 7.7 CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:L/A:N
ProductGitLab CE
Affected19.4.1-ce.0 (26212baacadb on the v19.4.1-ee tree)
Authauthenticated user, Gitea import, personal namespace
LicenseGNU Affero GPL v3.0
Lab127.0.0.1 only

What an attacker can do

Set Gitea Host URL to https://<name-they-control>/. UrlBlocker allows the first public A-record. HTTPS client_options keeps that hostname. Rebind to 127.0.0.1. Faraday GETs the catcher on the GitLab worker loopback. status.json provider_repos is whatever the catcher returned.

On all-in-one omnibus that is Workhorse, Puma, exporters, and anything else listening on the worker. Not host RCE. Not unauthenticated. HTTP Host URL stays on the pinned IP.

Same product, sibling leftovers: Gitaly fetch omits resolved_address, webhook 0.0.0.0/8.

How I found it

I read the 23 September 2026 19.4.1 / 19.3.3 / 19.2.7 patch notes first, then the v19.4.1-ee tree. CI regex RCE, MR diff XSS, Workhorse file.path read are closed on this pin. Import SSRF was not finished.

Import::GiteaController#client_options is the leftover:

host: verified_url.scheme == 'https' ? provider_url : verified_url.to_s,

HTTP uses verified_url (IP). HTTPS uses provider_url (the name the user typed). LegacyGithubImport::Client builds Octokit api_endpoint from that host. Gitlab::Octokit::UrlValidation calls validate! then @app.call(env) with no rewrite.

I stood up stock gitlab/gitlab-ce:19.4.1-ce.0. Local-requests off. Lab CA in /etc/gitlab/trusted-certs because Faraday ssl.verify is true. DNS for gitea.lab: lookups 1-2 return 1.1.1.1, later lookups return 127.0.0.1. Catcher shares the GitLab netns on :443. GET /import/gitea/status.json returned provider_repos named GITLAB-GITEA-IMPORT-SSRF-WITNESS. Catcher log: GET /api/v1/user/repos peer=127.0.0.1 host=gitea.lab.

Direct https://127.0.0.1/ : "Specified URL cannot be used". HTTP http://gitea.lab/ stayed on the pin and did not return the witness.

Wrong turns already recorded: /users/sign_in with Accept: application/json is 404 (HTML is 200); seed password CveLabRoot9! rejected because it contains root; CA bind-mount ro is EROFS after reconfigure links the file; first-two-then-loopback on lookup 2 makes UrlValidation block before Faraday connects. Pairs mode (odd public, even loopback) is what landed. A reverse shell. Theatre. The oracle is the witness in status.json plus the catcher peer.

Lab

cd lab
./run.sh

Target only http://127.0.0.1:18400. GitLab CE wants several GB RAM. First boot is slow. Authorized lab only.

status.json status=200 ... provider_repos ... GITLAB-GITEA-IMPORT-SSRF-WITNESS
catcher GET /api/v1/user/repos peer=127.0.0.1 host=gitea.lab status=200 witness=True
negative-a https://127.0.0.1 blocked
negative-b http://gitea.lab no-witness
SUCCESS GITLAB-GITEA-IMPORT-SSRF status.json mode=pairs http=200 GITLAB-GITEA-IMPORT-SSRF-WITNESS

The leftover

def client_options
  verified_url, provider_hostname = verify_blocked_uri
  {
    host: verified_url.scheme == 'https' ? provider_url : verified_url.to_s,
    api_version: 'v1',
    hostname: provider_hostname
  }
end

Use verified_url.to_s for https the same way HTTP already does. Rewrite env[:url] in Octokit UrlValidation to the pinned IP.

References

  • gitlab.com/gitlab-org/gitlab tag v19.4.1-ee
  • gitea_controller.rb · legacy_github_import/client.rb · octokit/url_validation.rb
  • Same product: gitlab-gitaly-fetch-ssrf · gitlab-webhook-0net-ssrf
  • CWE-918 · CWE-367

License

GNU Affero GPL v3.0. See LICENSE. Loopback lab only. No warranty.

Download Tool