GitLab MCP server's read-only mode and project allow-list bypassable via execute_graphql tool call
Undisclosed·@zereight/mcp-gitlab (gitlab-mcp MCP server)Fixed
A source-code security review found that the execute_graphql tool in the GitLab MCP server let an agent (or a malicious/prompt-injected client) issue GraphQL mutations that were misclassified as read-only because the write-detector regex didn't account for GraphQL's insignificant leading commas, and the same tool skipped the project-scope check other tools enforced, so arbitrary GitLab writes could reach any project the server's token could access even with read-only mode and a project allow-list configured.
- Blast radius
- Demonstrated via local/offline proof-of-concept only, no confirmed in-the-wild exploitation reported; any deployment of @zereight/mcp-gitlab before v2.1.30 relying on read-only mode or GITLAB_ALLOWED_PROJECT_IDS as its safety boundary was exposed to unauthorized writes up to the token's full privileges, plus (in related findings) unauthenticated remote control via Streamable HTTP/SSE transports and a ~1000-request session-exhaustion DoS.
- Root cause
- the read-only-mode write-detector stripped comments and strings but not GraphQL's insignificant commas, so a document like ',mutation{...}' was classified as read-only, and the execute_graphql handler was never wired to the project-scope enforcement function that every other tool called, so two separate safety controls were both silently no-ops for that one tool.
- How it was caught
- caught by an external source-code security review of the reviewed commit (not by runtime monitoring or an operator noticing abuse), and disclosed as GHSA-5648-rgj9-v224 with deterministic local PoCs for each defect.
- What changed
- maintainers released npm package v2.1.30, which parses execute_graphql with a real GraphQL parser to reject non-query operations, enforces project scope on that tool, extends the transport auth gate to cover cookie/OAuth startup modes, and enables DNS-rebinding protection with an allow-listed origin/host.
Take-awaywhen adding a new tool to an MCP server, don't assume it inherits the safety checks (read-only detection, scope allow-list, auth gating) applied elsewhere in the codebase — verify every tool handler independently calls the same enforcement functions, since agents will use exactly the tool that was missed.