MCP Atlassian: Arbitrary file read/exfiltration via upload_attachment missing validate_safe_path()GHSA-93xw-j965-9mx3
HIGHFix: sooperset/mcp-atlassian#1448GHSA-93xw-j965-9mx3 is a high-severity (CVSS 7.7) Path Traversal vulnerability in mcp-atlassian. A fix is available for mcp-atlassian — see the affected versions and patch details below.
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for GHSA-93xw-j965-9mx3.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
How urgent is this, really
GHSA-93xw-j965-9mx3 by exploitation likelihood (EPSS) against impact (CVSS). Outside the shaded patch-first corner.
Where this sits among everything scored
Of 394,803 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Counts from FIRST.org, log-scaled.
Real-World Exposure
mcp-atlassianReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
Summary
The upload_attachment method in confluence/attachments.py reads and uploads arbitrary local files to Confluence without calling validate_safe_path(). Both download methods (download_attachment at line 223, download_content_attachments at line 272) correctly call validate_safe_path() before writing files, but the upload path at lines 35-79 skips this check entirely.
An AI agent connected via MCP (or an attacker influencing that agent through prompt injection) can read any file on the host and exfiltrate it by uploading it as a Confluence page attachment.
Vulnerable Code
File: src/mcp_atlassian/confluence/attachments.py, lines 62-79
# No validate_safe_path() call anywhere in this method
if not os.path.isabs(file_path):
file_path = os.path.abspath(file_path)
if not os.path.exists(file_path):
return {"success": False, "error": f"File not found: {file_path}"}
filename = os.path.basename(file_path)
attachment = self._upload_attachment_direct(
content_id, file_path, filename, comment, minor_edit
)
The validate_safe_path function is already imported at line 9 of the same file, and used in the download methods. It was just not added to the upload path.
Proof of Concept
Tested with mcp-atlassian 0.21.1 on Python 3.11 (EC2, Amazon Linux 2023).
import inspect
from mcp_atlassian.confluence.attachments import AttachmentsMixin
# Confirm: no validate_safe_path in upload
source = inspect.getsource(AttachmentsMixin.upload_attachment)
assert "validate_safe_path" not in source # passes
# Confirm: validate_safe_path IS in downloads
assert "validate_safe_path" in inspect.getsource(AttachmentsMixin.download_attachment) # passes
assert "validate_safe_path" in inspect.getsource(AttachmentsMixin.download_content_attachments) # passes
An MCP tool call like this reads /etc/passwd and uploads it to Confluence:
{"tool": "confluence_upload_attachment", "arguments": {"content_id": "123456", "file_path": "/etc/passwd"}}
Impact
Exfiltration of any file readable by the MCP server process: SSH keys, AWS credentials, .env files, /etc/passwd, application secrets. Data leaves the local machine and lands on a remote Confluence instance accessible to other users.
Suggested Fix
Add validate_safe_path(file_path) before the os.path.exists() check in upload_attachment, matching the existing pattern in the download methods. The function is already imported.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | mcp-atlassian | all versions | 0.22.0pip install --upgrade 'mcp-atlassian==0.22.0' |
Affected Products
mcp atlassianmcp-atlassianDetection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for mcp-atlassian, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update mcp-atlassian to 0.22.0 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-93xw-j965-9mx3 is resolved across your whole dependency graph.
Workarounds
Resolve every user-supplied path to its canonical form and reject anything that escapes the intended directory, and run the component under an account that has no read or write access outside the directory it legitimately serves.
Frequently Asked Questions
Is GHSA-93xw-j965-9mx3 in your dependencies?
Find it across PyPI, including transitive dependencies.