CVE-2026-77262: MCP Atlassian: Path Traversal / Arbitrary File Read in confluence_upload_attachment MCP tool (incomplete fix of GHSA-xjgw-4wvw-rgm4)
The `confluence_upload_attachment` tool in mcp-atlassian passes its `file_path` argument straight to `open()`, so anyone who can call the tool can read server files and send them in a multipart upload. The reporter says the default streamable-http setup needs no credentials. Listed as fixed in 0.22.0.
Published Sep 22, 2026 · Analysis Oct 22, 2026
What an attacker can do
The sink is confluence/attachments.py:477, which opens file_path and posts it to /wiki/rest/api/content/{page_id}/child/attachment. The tool definition in servers/confluence.py declares file_path as "Absolute path to the file to upload", with no pattern or validator. The download code calls validate_safe_path() at lines 223 and 272, a fix that shipped in v0.17.0 for GHSA-xjgw-4wvw-rgm4 (CVE-2026-27825). The upload path was left out. The check_write_access decorator only honours READ_ONLY_MODE, which is off by default.
The reporter says the default transport is streamable-http bound to 0.0.0.0 with no authentication layer, so a network attacker can call tools directly. They scored that case 9.3 under CVSS 3.1; the stdio-only case scores 6.6. The data panel carries the maintainers' 8.6.
In the proof of concept, a mock Confluence stub captured a 3339-byte body containing the contents of /etc/passwd, and the tool returned a success message. Targets include ~/.aws/credentials, ~/.ssh/id_rsa, .env files and the Kubernetes service-account token. The upload leaves no error trace. A prompt-injected assistant can also be coaxed into calling the tool with a sensitive path.
Who is affected
The packages list marks mcp-atlassian below 0.22.0 as vulnerable. The advisory text says the read-side bug has existed since v0.17.0 and describes no patched version at disclosure, but the package data and release tag v0.22.0 give 0.22.0 as the fix.
pip show mcp-atlassianExposure is greatest for servers reachable over the network with the HTTP transport and for agents that read untrusted pages.
mcp-atlassian
- Ecosystem
- PyPI
- Affected
- < 0.22.0
- Fixed in
- 0.22.0
- Check
pip show mcp-atlassian
How to fix it
Upgrade to 0.22.0:
pip install --upgrade mcp-atlassian==0.22.0The fix is pull request 1448. The reporter also recommends binding streamable-http to 127.0.0.1 or requiring an auth token on non-loopback interfaces, and confining upload paths to an operator-chosen directory. Set READ_ONLY_MODE=true if you do not need write tools. Rotate any credential that sat in files the server user can read if the service was exposed.
How to tell if you were hit
Review Confluence for attachments you did not create, and check the audit log for uploads from the integration account. In MCP request logs, search for confluence_upload_attachment with file_path values such as /etc/passwd, .ssh/id_rsa or /var/run/secrets. Check the HTTP port for connections from unknown hosts. If your Confluence URL could have been changed, also check outbound connections to unexpected hosts. Beam records agent MCP tool calls, which covers the prompt-injection route.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
Summary
mcp-atlassian exposes an MCP tool confluence_upload_attachment whose file_path argument is passed directly to open(file_path, "rb") without any path validation. An attacker able to invoke the tool can read arbitrary files readable by the server process and exfiltrate them into a multipart upload directed at an attacker-controlled Confluence host. In the default streamable-http transport the server binds 0.0.0.0 with no built-in authentication, making this remotely exploitable without credentials.
This is the read-side symmetric twin of GHSA-xjgw-4wvw-rgm4 / CVE-2026-27825 (fixed in v0.17.0). The v0.17.0 patch only covered the download/write path; the upload path that reads local files was left unguarded.
Details
Vulnerable sink
src/mcp_atlassian/confluence/attachments.py:477
with open(file_path, "rb") as fp:
files = {"file": (filename, fp, content_type)}
response = self.confluence.session.post(url, files=files, ...)file_path is attacker-controlled end-to-end.
Taint source
src/mcp_atlassian/servers/confluence.py:1290-1369, tool definition at :1307:
file_path: Annotated[str, Field(description="Absolute path to the file to upload")]No Pydantic pattern=, no validator, no validate_safe_path() call.
Call chain
- MCP client invokes
confluence_upload_attachment(page_id, file_path, ...) - Server handler forwards to
ConfluenceFetcher.upload_attachment(file_path) _upload_attachment_direct(file_path)callsopen(file_path, "rb")- File bytes are streamed in the multipart body of
POST /wiki/rest/api/content/{page_id}/child/attachmentto the configured Confluence base URL — which the attacker also controls (they providedCONFLUENCE_URLvia env/config or target a server they already control).
Asymmetry with the patched download path
attachments.py:223(download) — callsvalidate_safe_path(local_path)beforeopen(..., "wb")attachments.py:272(download) — callsvalidate_safe_path(local_path)beforeopen(..., "wb")attachments.py:477(upload) — no validation
The check_write_access decorator does not help: it only gates READ_ONLY_MODE (default false) and is unrelated to filesystem path safety.
Default exposure
src/mcp_atlassian/__init__.py:151 and :360 — default transport is streamable-http binding HOST=0.0.0.0 with no auth layer. Any network-reachable attacker can call MCP tools directly.
Severity
Primary (default `streamable-http` deployment)
- Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:N/A:N - Score: 9.3 Critical
- Rationale: network-reachable, unauthenticated, scope-changed because files outside the MCP server's intended resource boundary (Confluence attachments) are exfiltrated.
Alternative (stdio-only deployment, conservative)
- Vector:
CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N - Score: 6.6 High
- Rationale: local attacker controlling the MCP client context.
Maintainer should pick the vector that reflects the documented default deployment.
CWE
CWE-22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
Affected
- Product:
sooperset/mcp-atlassian - Affected versions: >= 0.17.0, <= HEAD (`d8bc78698a63cb6b321c7ca796d6329d448f7f6d`)
- Note: v0.17.0 is the fix commit for GHSA-xjgw-4wvw-rgm4 but only addressed the write-side. This read-side twin has existed since that release and remains unpatched on
main. - Patched versions: none at time of disclosure
Proof of Concept
Fully reproduced twice end-to-end against a local stdlib HTTP stub acting as the Confluence API, driven by a real MCP stdio client (mcp.ClientSession + stdio_client) spawning the unmodified mcp-atlassian server at HEAD.
Permalinks (commit-pinned)
- Sink: https://github.com/sooperset/mcp-atlassian/blob/d8bc78698a63cb6b321c7ca796d6329d448f7f6d/src/mcp_atlassian/confluence/attachments.py#L477
- Source (tool def): https://github.com/sooperset/mcp-atlassian/blob/d8bc78698a63cb6b321c7ca796d6329d448f7f6d/src/mcp_atlassian/servers/confluence.py#L1307
- Safe download comparison: https://github.com/sooperset/mcp-atlassian/blob/d8bc78698a63cb6b321c7ca796d6329d448f7f6d/src/mcp_atlassian/confluence/attachments.py#L223
- Default transport bind: https://github.com/sooperset/mcp-atlassian/blob/d8bc78698a63cb6b321c7ca796d6329d448f7f6d/src/mcp_atlassian/__init__.py#L151
Reproduction
- Start mock Confluence stub:
python mock_confluence.py(binds127.0.0.1:8443, logs all multipart bodies) - Launch MCP client against real
mcp-atlassianserver over stdio withCONFLUENCE_URL=http://127.0.0.1:8443 - Call tool:
{
"name": "confluence_upload_attachment",
"arguments": {
"page_id": "123456",
"file_path": "/etc/passwd",
"comment": "poc"
}
}Run 1 — /etc/passwd
- MCP response:
isError=False,{"message": "Attachment uploaded successfully"} - Stub captured 3339-byte multipart body containing:
root:x:0:0:root:/root:/bin/bash(and full passwd contents)
Run 2 — /etc/hostname
- MCP response:
isError=False, same success envelope - Stub captured 380-byte body containing:
ang3l-pc
Both runs used unmodified server code at commit d8bc78698a63cb6b321c7ca796d6329d448f7f6d. PoC artifacts (mock_confluence.py, mcp_client.py, poc_run1.sh, poc_run2.sh, asymmetry.txt, ENVIRONMENT.md) available on request to maintainers via this advisory thread.
Impact
- Arbitrary file read of anything readable by the server process UID:
/etc/passwd,/etc/shadow(if running as root in container),~/.aws/credentials,~/.ssh/id_rsa,.envfiles, kube service-account tokens at/var/run/secrets/kubernetes.io/serviceaccount/token, application source, database dumps, private keys. - Exfiltration is covert: file bytes transit to the attacker's configured Confluence host inside a normal-looking multipart upload. No error surface; the tool returns success.
- In the default
streamable-http0.0.0.0 deployment, no credentials are required. - Chains trivially with any AI agent that exposes this MCP server to untrusted prompt input — a prompt-injected assistant can be coerced into calling the tool with a sensitive path.
Relationship to GHSA-xjgw-4wvw-rgm4 (CVE-2026-27825)
GHSA-xjgw-4wvw-rgm4 (CVSS 9.1, fixed in v0.17.0) addressed an arbitrary file write in the same attachments.py module: attacker-controlled paths reaching open(..., "wb") on the download side. The fix introduced validate_safe_path() and applied it at lines 223 and 272.
The upload-side counterpart at line 477 was not updated. Same module, same maintainer, same class of bug (unchecked path → open()), opposite direction (read vs write). This advisory reports the incomplete-fix twin.
Remediation
Required
Call validate_safe_path(file_path) at the top of ConfluenceFetcher.upload_attachment and _upload_attachment_direct in src/mcp_atlassian/confluence/attachments.py, mirroring the download path at lines 223 and 272. Reject absolute paths outside a configurable allow-listed upload directory and reject any path containing .. after normalization.
Defense in depth
Tighten the Pydantic tool schema at src/mcp_atlassian/servers/confluence.py:1307:
file_path: Annotated[
str,
Field(
description="Relative path within the configured upload directory",
pattern=r"^(?!/)(?!.*\.\.)[\w\-./]+$",
),
]This blocks absolute paths and .. at the MCP schema layer before the handler is even entered.
Additional hardening (out of scope but recommended)
- Default
streamable-httpto127.0.0.1instead of0.0.0.0, or require an auth token when bound to a non-loopback interface. - Document that
file_pathmust be confined to an operator-chosen directory and expose that directory via config.
Credited to romain-deperne.
Questions
- How is this different from CVE-2026-27825?
CVE-2026-27825 was an arbitrary file write on the download path, fixed in v0.17.0. This one reads files on the upload path, which that fix left unguarded.
- Does it need credentials?
The reporter says not in the default streamable-http setup, which binds 0.0.0.0 without auth. Under stdio, the attacker must control the MCP client or steer the agent.
- Why does the advisory text say there is no patch?
That sentence reflects the time of disclosure. The package data lists 0.22.0 as patched.
- Is it exploited in the wild?
No source says so. The reporter reproduced it twice against a local mock Confluence server.
References
How this page is made: the data panel comes from the GitHub Advisory Database, CISA’s KEV catalog, the NVD and FIRST EPSS, and updates twice a day. The analysis is written by an AI model from the sources listed above and checked by automated rules before it is published. Check versions against the vendor's advisory before you act. Methodology
More Other MCP servers and tools vulnerabilities
All Other MCP servers and tools entriesCVE-2026-77361
obsidian-tc : Symlink read-ACL scope bypass via lexical path checks
medium4.7Oct 23, 2026CVE-2026-114126
Storybook dev server vulnerable to code injection from the local network
high8.7Oct 22, 2026CVE-2026-113731
djust: Arbitrary absolute-path file read in the find_handlers_for_template MCP tool
low3.3Oct 21, 2026CVE-2026-114125
Storybook: Missing origin validation in Storybook preview allows code injection from malicious websites
critical9.4Oct 21, 2026CVE-2026-111770
MCP TypeScript server SDK: Shared transport or server instances delivered one HTTP client's messages to another
high7.7Oct 20, 2026GHSA-953h-535j-jg2v
agent-router: MCP session resume does not verify the embedded anti-hijacking subject; default Helm seed makes session IDs forgeable
medium6.8Oct 19, 2026
