CVE-2026-61568
@zereight/mcp-gitlab: DNS rebinding reaches local Streamable HTTP MCP transport
@zereight/mcp-gitlab is a Model Context Protocol server for GitLab. Versions prior to 2.1.30 expose the Streamable HTTP MCP endpoint without an effective Host or Origin allowlist. A malicious web page can use DNS rebinding to route browser requests to a victim's local MCP listener while preserving an attacker-controlled Host and Origin. The server accepts those headers and reaches the MCP initialization path instead of rejecting the request at the HTTP boundary. Version 2.1.30 contains a patch.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- Required
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
9.6
@zereight/mcp-gitlab: DNS rebinding reaches local Streamable HTTP MCP transport
@zereight/mcp-gitlab is a Model Context Protocol server for GitLab. Versions prior to 2.1.30 expose the Streamable HTTP MCP endpoint without an effective Host or Origin allowlist. A malicious web page can use DNS rebinding to route browser requests to a victim's local MCP listener while preserving an attacker-controlled Host and Origin. The server accepts those headers and reaches the MCP initialization path instead of rejecting the request at the HTTP boundary. Version 2.1.30 contains a patch.
- Record
CVE-2026-61568- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H - Weakness
- CWE-350
- Updated
- 2026-11-02
EUVDEUVD-2026-79999
9.6
@zereight/mcp-gitlab is a Model Context Protocol server for GitLab. Versions prior to 2.1.30 expose the Streamable HTTP MCP endpoint without an effective Host or Origin allowlist. A malicious web page can use DNS rebinding to route browser requests to a victim's local MCP listener while preserving an attacker-controlled Host and Origin. The server accepts those headers and reaches the MCP initialization path instead of rejecting the request at the HTTP boundary. Version 2.1.30 contains a patch.
- Record
EUVD-2026-79999- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-vmp7-252j-cwp7
9.6
@zereight/mcp-gitlab: DNS rebinding reaches local Streamable HTTP MCP transport
@zereight/mcp-gitlab exposes its Streamable HTTP MCP endpoint without an effective Host or Origin allowlist. A malicious web page can use DNS rebinding to route browser requests to a victim's local MCP listener while preserving an attacker-controlled Host and Origin. The server accepts those headers and reaches the MCP initialization path instead of rejecting the request at the HTTP boundary.
This is CWE-350, Reliance on Reverse DNS Resolution for a Security-Critical Action. The affected package is @zereight/mcp-gitlab version 2.1.18 at commit 74a8c834424ff557ad8bc6f225e4dc5acf80aa13.
The vulnerable transport setup is in index.ts. Express JSON parsing is installed globally before any MCP route-level Host or Origin allowlist:
// index.ts:12077
app.use(express.json());
registerDownloadProxy(app);
The Streamable HTTP transport is then created without the SDK DNS-rebinding controls:
// index.ts:12375
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (newSessionId: string) => {
streamableTransports[newSessionId] = transport;
metrics.totalSessions++;
metrics.activeSessions++;
},
});
The transport constructor does not set enableDnsRebindingProtection, allowedHosts, or allowedOrigins. The server also does not add an Express middleware that rejects unexpected Host or Origin headers before /mcp.
The default host is loopback, which is the exact target DNS rebinding attacks are designed to reach:
// config.ts:192
export const HOST = getConfig("host", "HOST") || "127.0.0.1";
// config.ts:196
export const PORT = _intEnv("PORT", "port", _PORT_DEFAULT);
The README documents Streamable HTTP as a supported transport for modern remote deployments and documents REMOTE_AUTHORIZATION=true for multi-user HTTP deployments. In that mode, unauthenticated tools/list and material GitLab API tool calls are blocked by token checks. The Host/Origin defect is still present at the browser boundary: the server accepts attacker-controlled browser-origin headers and processes the MCP initialize request instead of rejecting the connection as cross-origin localhost access.
Proof of concept
The following reproduction uses a fake GitLab API with planted data. It proves the HTTP boundary failure and the token boundary separately:
- no-token
initializesucceeds with attacker-controlledHostandOrigin; - no-token
tools/listis rejected with401; - the same forged-origin flow with a planted
Private-Tokenlists tools and callslist_project_variables; - the fake GitLab API records the forwarded token and returns a planted fake project variable.
Start the fake GitLab API:
python3 - <<'PY'
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import parse_qs, urlparse
WITNESS = "/tmp/zereight-gitlab-mcp-rebind-witness.jsonl"
PROJECT_ID = "pluto/rebind-target"
FAKE_SECRET = "glpat-FAKE-PROJECT-CI-SECRET-0001"
class Handler(BaseHTTPRequestHandler):
def _json(self, status, payload):
data = json.dumps(payload).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def _record(self):
parsed = urlparse(self.path)
with open(WITNESS, "a", encoding="utf-8") as f:
f.write(json.dumps({
"method": self.command,
"path": parsed.path,
"query": parse_qs(parsed.query),
"authorization": self.headers.get("authorization"),
"private_token": self.headers.get("private-token"),
"job_token": self.headers.get("job-token"),
}, sort_keys=True) + "\n")
def do_GET(self):
self._record()
path = urlparse(self.path).path
…
- Record
GHSA-vmp7-252j-cwp7- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H - Weakness
- CWE-350
- Updated
- 2026-11-02
NVD
9.6
@zereight/mcp-gitlab is a Model Context Protocol server for GitLab. Versions prior to 2.1.30 expose the Streamable HTTP MCP endpoint without an effective Host or Origin allowlist. A malicious web page can use DNS rebinding to route browser requests to a victim's local MCP listener while preserving an attacker-controlled Host and Origin. The server accepts those headers and reaches the MCP initialization path instead of rejecting the request at the HTTP boundary. Version 2.1.30 contains a patch.
- Record
CVE-2026-61568- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H - Weakness
- CWE-350
- Updated
- 2026-11-02
OSV
9.6
@zereight/mcp-gitlab: DNS rebinding reaches local Streamable HTTP MCP transport
@zereight/mcp-gitlab is a Model Context Protocol server for GitLab. Versions prior to 2.1.30 expose the Streamable HTTP MCP endpoint without an effective Host or Origin allowlist. A malicious web page can use DNS rebinding to route browser requests to a victim's local MCP listener while preserving an attacker-controlled Host and Origin. The server accepts those headers and reaches the MCP initialization path instead of rejecting the request at the HTTP boundary. Version 2.1.30 contains a patch.
- Record
CVE-2026-61568- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H - Weakness
- CWE-350
- Updated
- 2026-11-02
OSVGHSA-vmp7-252j-cwp7
9.6
@zereight/mcp-gitlab: DNS rebinding reaches local Streamable HTTP MCP transport
@zereight/mcp-gitlab exposes its Streamable HTTP MCP endpoint without an effective Host or Origin allowlist. A malicious web page can use DNS rebinding to route browser requests to a victim's local MCP listener while preserving an attacker-controlled Host and Origin. The server accepts those headers and reaches the MCP initialization path instead of rejecting the request at the HTTP boundary.
This is CWE-350, Reliance on Reverse DNS Resolution for a Security-Critical Action. The affected package is @zereight/mcp-gitlab version 2.1.18 at commit 74a8c834424ff557ad8bc6f225e4dc5acf80aa13.
The vulnerable transport setup is in index.ts. Express JSON parsing is installed globally before any MCP route-level Host or Origin allowlist:
// index.ts:12077
app.use(express.json());
registerDownloadProxy(app);
The Streamable HTTP transport is then created without the SDK DNS-rebinding controls:
// index.ts:12375
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (newSessionId: string) => {
streamableTransports[newSessionId] = transport;
metrics.totalSessions++;
metrics.activeSessions++;
},
});
The transport constructor does not set enableDnsRebindingProtection, allowedHosts, or allowedOrigins. The server also does not add an Express middleware that rejects unexpected Host or Origin headers before /mcp.
The default host is loopback, which is the exact target DNS rebinding attacks are designed to reach:
// config.ts:192
export const HOST = getConfig("host", "HOST") || "127.0.0.1";
// config.ts:196
export const PORT = _intEnv("PORT", "port", _PORT_DEFAULT);
The README documents Streamable HTTP as a supported transport for modern remote deployments and documents REMOTE_AUTHORIZATION=true for multi-user HTTP deployments. In that mode, unauthenticated tools/list and material GitLab API tool calls are blocked by token checks. The Host/Origin defect is still present at the browser boundary: the server accepts attacker-controlled browser-origin headers and processes the MCP initialize request instead of rejecting the connection as cross-origin localhost access.
Proof of concept
The following reproduction uses a fake GitLab API with planted data. It proves the HTTP boundary failure and the token boundary separately:
- no-token
initializesucceeds with attacker-controlledHostandOrigin; - no-token
tools/listis rejected with401; - the same forged-origin flow with a planted
Private-Tokenlists tools and callslist_project_variables; - the fake GitLab API records the forwarded token and returns a planted fake project variable.
Start the fake GitLab API:
python3 - <<'PY'
import json
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
from urllib.parse import parse_qs, urlparse
WITNESS = "/tmp/zereight-gitlab-mcp-rebind-witness.jsonl"
PROJECT_ID = "pluto/rebind-target"
FAKE_SECRET = "glpat-FAKE-PROJECT-CI-SECRET-0001"
class Handler(BaseHTTPRequestHandler):
def _json(self, status, payload):
data = json.dumps(payload).encode()
self.send_response(status)
self.send_header("Content-Type", "application/json")
self.send_header("Content-Length", str(len(data)))
self.end_headers()
self.wfile.write(data)
def _record(self):
parsed = urlparse(self.path)
with open(WITNESS, "a", encoding="utf-8") as f:
f.write(json.dumps({
"method": self.command,
"path": parsed.path,
"query": parse_qs(parsed.query),
"authorization": self.headers.get("authorization"),
"private_token": self.headers.get("private-token"),
"job_token": self.headers.get("job-token"),
}, sort_keys=True) + "\n")
def do_GET(self):
self._record()
path = urlparse(self.path).path
…
- Record
GHSA-vmp7-252j-cwp7- CVSS 3.1
- 9.6 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H - Weakness
- CWE-350
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
@zereight/mcp-gitlabnpm |
before 2.1.30 | 2.1.30 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-61568 is a critical vulnerability (CVSS 9.6) in Zereight Gitlab-mcp, published September 15, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.53%, the 45th percentile. Fixed in @zereight/mcp-gitlab 2.1.30.
References
github.com/zereight/gitlab-mcp/security/advisories/GHSA-vmp7-252j-cwp7
github.com/zereight/gitlab-mcp/pull/555
github.com/zereight/gitlab-mcp/commit/52207c6f5c0e7a39e9235d491225edbb562a0290
github.com/zereight/gitlab-mcp/releases/tag/v2.1.30
github.com/advisories/GHSA-vmp7-252j-cwp7
github.com/CVEProject/cvelistV5/tree/main/cves/2026/61xxx/CVE-2026-61568.json
nvd.nist.gov/vuln/detail/CVE-2026-61568
github.com/zereight/gitlab-mcp
Left out here: the rest of 2 source descriptions. The JSON record has them.