Every CVE Search/ Get API key

CVE-2026-61568

@zereight/mcp-gitlab: DNS rebinding reaches local Streamable HTTP MCP transport

9.6 CriticalFix available

@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

0.53%Up 0.2 points since Sep 16, 2026
90%50%10%1%

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 CriticalCVSS: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 CriticalCVSS: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 initialize succeeds with attacker-controlled Host and Origin;
  • no-token tools/list is rejected with 401;
  • the same forged-origin flow with a planted Private-Token lists tools and calls list_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 CriticalCVSS: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 CriticalCVSS: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 CriticalCVSS: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 initialize succeeds with attacker-controlled Host and Origin;
  • no-token tools/list is rejected with 401;
  • the same forged-origin flow with a planted Private-Token lists tools and calls list_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 CriticalCVSS: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

Affected packages
PackageAffectedFixed
@zereight/mcp-gitlab
npm
before 2.1.30
2.1.30

History

History
RecordedChangedSources
first indexedCVE 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

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open