VulnWatch VulnWatch
← Back to dashboard
High github · GHSA-p6hp-93wp-fh6p

MCP Atlassian: Path Traversal / Arbitrary File Read in confluence_upload_attachment MCP tool (incomplete fix of GHSA-xjgw-4wvw-rgm4)

Published Sep 22, 2026 CVSS 8.6

Summary

mcp-atlassian exposes an MCP tool confluence_upload_attachment whose file_path argument is passed directly to open(file_path, "rb") without any path validation. An attacker able to invoke the tool can read arbitrary files readable by the server process and exfiltrate them into a multipart upload directed at an attacker-controlled Confluence host. In the default streamable-http transport the server binds 0.0.0.0 with no built-in authentication, making this remotely exploitable without credentials.

This is the read-side symmetric twin of GHSA-xjgw-4wvw-rgm4 / CVE-2026-27825 (fixed in v0.17.0). The v0.17.0 patch only covered the download/write path; the upload path that reads local files was left unguarded.

Details

Vulnerable sink

src/mcp_atlassian/confluence/attachments.py:477

with open(file_path, "rb") as fp:
    files = {"file": (filename, fp, content_type)}
    response = self.confluence.session.post(url, files=files, ...)

file_path is attacker-controlled end-to-end.

Taint source

src/mcp_atlassian/servers/confluence.py:1290-1369, tool definition at :1307:

file_path: Annotated[str, Field(description="Absolute path to the file to upload")]

No Pydantic pattern=, no validator, no validate_safe_path() call.

Call chain

  1. MCP client invokes confluence_upload_attachment(page_id, file_path, ...)
  2. Server handler forwards to ConfluenceFetcher.upload_attachment(file_path)
  3. _upload_attachment_direct(file_path) calls open(file_path, "rb")
  4. File bytes are streamed in the multipart body of POST /wiki/rest/api/content/{page_id}/child/attachment to the configured Confluence base URL — which the attacker also controls (they provided CONFLUENCE_URL via env/config or target a server they already control).

Asymmetry with the patched download path

  • attachments.py:223 (download) — calls validate_safe_path(local_path) before open(..., "wb")
  • attachments.py:272 (download) — calls validate_safe_path(local_path) before open(..., "wb")
  • attachments.py:477 (upload) — no validation

The check_write_access decorator does not help: it only gates READ_ONLY_MODE (default false) and is unrelated to filesystem path safety.

Default exposure

src/mcp_atlassian/__init__.py:151 and :360 — default transport is streamable-http binding HOST=0.0.0.0 with no auth layer. Any network-reachable attacker can call MCP tools directly.

Severity

Primary (default streamable-http deployment)

  • Vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
  • Score: 9.3 Critical
  • Rationale: network-reachable, unauthenticated, scope-changed because files outside the MCP server's intended resource boundary (Confluence attachments) are exfiltrated.

Alternative (stdio-only deployment, conservative)

  • Vector: CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N
  • Score: 6.6 High
  • Rationale: local attacker controlling the MCP client context.

Maintainer should pick the vector that reflects the documented default deployment.

CWE

CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

Affected

  • Product: sooperset/mcp-atlassian
  • Affected versions: **>= 0.17.0,

Affected AI Products

mcp server ai agent
Get the weekly digest. Every Monday: top AI security stories of the week. Free.