Do NOT open a public issue for security vulnerabilities.
The preferred channel is GitHub Security Advisories, which keeps the report private until a coordinated fix is published.
Please include:
- A clear description of the vulnerability and its potential impact.
- Steps to reproduce (proof-of-concept code, request samples, or affected configuration).
- Affected version(s) —
gitlab-mcp-server --versionoutput and commit hash if built from source. - Environment (OS, GitLab version, transport: stdio or HTTP, MCP client).
- Any suggested mitigation, if known.
If GitHub Security Advisories is unavailable to you, contact the maintainer privately via direct message on GitHub (@jmrplens). Do not send sensitive details over public channels.
English (preferred) or Spanish.
| Stage | Target |
|---|---|
| Acknowledgement of report | within 48 hours |
| Initial triage and severity | within 7 days |
| Fix for Critical / High | within 30 days of confirmation |
| Fix for Medium / Low | within 90 days of confirmation |
| Public disclosure / advisory | after a fix is released, with a typical 7-day embargo so users can update |
These targets are best-effort for a maintainer-driven open-source project. We will keep you informed of progress and any expected delay.
gitlab-mcp-server sits between an AI client and a GitLab instance. It holds a
credential that usually carries the full api scope, it takes instructions from
a model, and it relays content written by other people — issue titles, MR
descriptions, commit messages, file contents, job logs — back to that model.
That shape is what determines whether something counts as a vulnerability here.
Trust boundaries. Three of them matter:
- Model → server. Tool arguments arrive from a model that may have been influenced by content it read earlier. The server must not treat an argument as authority to exceed the token's own permissions, and must not let an argument redirect a request to an unintended host or path.
- GitLab → server → model. Everything the GitLab API returns is attacker-
influenced whenever an attacker can file an issue, open an MR, or push a
commit. It is rendered into tool results through the escaping helpers in
internal/toolutil/text.go, so a way to break out of a table cell, a code fence, or a heading is a vulnerability. - Tenant → tenant (HTTP mode). One process serves many callers. The bounded
per-token+URL server pool in
internal/serverpool/is what keeps one caller's token, client, and cached tier from reaching another caller's session.
What we consider a vulnerability, specifically:
- Credential disclosure. A PAT or OAuth token reaching a log line, an error
message, a tool result, an MCP resource, or a crash dump. Tokens are meant to
stay in memory and in the operator's
.env, never in model-visible output. - Prompt injection escaping its labelling. Externally controlled GitLab text that can be made to read to the calling model as an instruction rather than as quoted data. The payload originating on GitLab does not put it out of scope — how this server frames that text is our responsibility.
- Cross-tenant leakage in HTTP mode. Any path by which one bearer token observes another's GitLab client, cached identity, tier, or tool results, or by which pool eviction serves a session the wrong client.
- Privilege escalation past the configured mode.
GITLAB_READ_ONLY=trueandGITLAB_SAFE_MODE=trueare enforcement, not hints. A mutating call that executes despite either flag is a vulnerability, including through the dynamicgitlab_execute_actionsurface. - Path traversal on file operations. Upload and file-content tools take caller-supplied paths; one that escapes its intended directory or reads something the operator did not expose is a vulnerability.
- Server-side request forgery. A caller-controlled value that redirects an
API request away from the configured
GITLAB_URLto an internal address. - Update-channel compromise. Auto-update fetches and replaces the running binary. A way to make it install an unverified or substituted artifact is a vulnerability regardless of how the release was produced.
Assumptions we make. The operator is trusted and chooses the token and its scope; the GitLab instance enforces its own authorization, and this server never tries to widen what the token already allows; the host running the server is not already compromised. Reports resting on breaking one of those assumptions fall under Out of scope below.
- The
gitlab-mcp-serversource code in this repository (Go server, MCP tools, transports, prompts, resources). - Authentication and authorization handling (token storage, OAuth flows, HTTP session isolation).
- Input validation in MCP tool handlers.
- Path handling for file uploads and downloads.
- TLS configuration handling and
GITLAB_SKIP_TLS_VERIFYsemantics. - Error messages and logs that could leak credentials or sensitive metadata.
- Released binaries and Docker images published from this repository.
- Auto-update mechanism (signature verification, integrity checks).
- Vulnerabilities in the GitLab server itself — please report those to GitLab.
- Vulnerabilities in upstream dependencies that have already been disclosed and patched upstream — open a regular issue or PR to bump the dependency instead.
- Misconfigurations of the operator's environment (leaked PATs, world-readable
.env, exposed HTTP port without authentication, etc.) that are explicitly warned against in the documentation. - Issues that require the attacker to already control the host running the server (kernel exploits, container escapes, side-channel attacks on memory).
- Denial-of-service via legitimate but expensive GitLab API queries (rate limiting is the operator's responsibility).
- Findings from automated scanners without a demonstrated impact (please include a working PoC).
Security fixes are issued for the latest stable release line on main. Older releases do not receive backports.
| Version | Supported |
|---|---|
Latest 1.x release |
✅ |
Older 1.x releases |
❌ (please update) |
0.x (pre-1.0) |
❌ |
We strongly recommend running the most recent release. The auto-update mechanism (AUTO_UPDATE=true, default) keeps the binary current.
We follow a coordinated disclosure model aligned with ISO/IEC 29147 and the OWASP Vulnerability Disclosure Cheat Sheet:
- You report privately via GitHub Security Advisories.
- We acknowledge, triage, and confirm the issue.
- We develop and test a fix in a private fork.
- We release the fix and publish a GitHub Security Advisory (and request a CVE when applicable).
- After a typical 7-day embargo, full technical details may be disclosed publicly.
If a vulnerability is being actively exploited in the wild, we may shorten or skip the embargo to protect users.
We support good-faith security research on this project. If you make a reasonable effort to comply with this policy, we will:
- Consider your research authorized under our terms of use.
- Work with you to understand and resolve the issue quickly.
- Not pursue or support legal action against you, or report you to law enforcement, for accidental or good-faith violations.
- Recognise your contribution publicly (see Credit) unless you prefer to remain anonymous.
To stay within safe harbor, you must:
- Only test against your own deployment of
gitlab-mcp-server(do not target third-party hosts or organizations). - Avoid privacy violations, data destruction, and service degradation of others.
- Stop testing and report immediately if you encounter user data, credentials, or PII.
- Give us reasonable time to remediate before any public disclosure.
This safe-harbor language is inspired by disclose.io core terms.
- We are happy to credit reporters in the published advisory and release notes (handle, real name, or anonymous — your choice).
- For qualifying issues we will request a CVE through GitHub's CNA and reference it in the advisory.
- There is currently no monetary bug bounty.
The remainder of this document describes how the server handles security-sensitive concerns. Operators should review these to harden their deployments.
- The GitLab Personal Access Token is provided via
GITLAB_TOKENenvironment variable (stdio mode) or per-request HTTP header (HTTP mode). - Tokens are never logged, displayed in tool output, or included in error messages.
- In HTTP mode, each client authenticates via
PRIVATE-TOKENorAuthorization: Bearerheader — tokens are isolated per session. - The
.envfile containing credentials is excluded from version control via.gitignore.
gitlab_project_uploadaccepts afile_pathto read a local file from the MCP server's filesystem (an alternative tocontent_base64).- The server reads any path its process can access, so run it with least privilege and treat
file_pathas trusted input from the MCP client. - Prefer
content_base64when the caller should not be able to read arbitrary server-side files.
- TLS certificate verification is enabled by default.
- Self-signed certificates can be accepted via
GITLAB_SKIP_TLS_VERIFY=true. - This setting should only be used in trusted internal networks.
- Set
GITLAB_READ_ONLY=trueto disable all mutating tools (create, update, delete). Only read-only tools (list, get, search) are registered. - Set
GITLAB_SAFE_MODE=trueto intercept mutating tools and return a JSON preview instead of executing the change. - Both flags provide additional protection for sensitive GitLab instances.
- All tool inputs are validated before GitLab API calls.
- Required parameters are checked explicitly — missing values produce clear error messages.
- Integer IDs are validated to prevent injection.
- String parameters are sanitized where applicable.
- Error messages never expose internal server details or stack traces.
- API errors from GitLab are wrapped with context but sensitive headers are stripped.
- Authentication failures return generic messages without revealing credential details.
- Minimal dependency footprint.
- Dependencies are tracked in
go.sumwith cryptographic checksums. - Regular dependency updates are performed to address known vulnerabilities (
govulncheckruns in CI). - Automated dependency scanning via Dependabot.
- Release binaries are built from tagged commits and published via GoReleaser.
- Checksums (
checksums.txt) and a Cosign/Sigstore signature bundle (checksums.txt.sigstore.json) are attached to every GitHub Release. Verify withcosignusing the keyless GitHub OIDC identity of this repository. - The auto-update mechanism verifies integrity against published checksums before replacing the running binary.
- Use a dedicated GitLab token with minimal required scopes (prefer
read_apifor read-only use cases). - Run the server as a non-privileged user — avoid root/administrator.
- Enable TLS between the MCP server and GitLab instance in production.
- Keep the
.envfile permissions restrictive (chmod 600on Unix systems). - Run the server with least privilege so
file_pathuploads cannot read sensitive files (or usecontent_base64). - Use read-only or safe mode (
GITLAB_READ_ONLY=trueorGITLAB_SAFE_MODE=true) when mutation is not needed or must be reviewed. - Monitor token usage via GitLab's admin panel.
- Rotate tokens periodically according to your organization's policy.
- In HTTP mode, restrict network access to trusted clients only and consider running behind a TLS-terminating reverse proxy.
- Keep
gitlab-mcp-serverupdated — enableAUTO_UPDATE=true(default) or subscribe to repository releases.