GHSA-93XW-J965-9MX3

Vulnerability from github – Published: 2026-09-22 20:36 – Updated: 2026-09-22 20:36
VLAI
Summary
MCP Atlassian: Arbitrary file read/exfiltration via upload_attachment missing validate_safe_path()
Details

Summary

The upload_attachment method in confluence/attachments.py reads and uploads arbitrary local files to Confluence without calling validate_safe_path(). Both download methods (download_attachment at line 223, download_content_attachments at line 272) correctly call validate_safe_path() before writing files, but the upload path at lines 35-79 skips this check entirely.

An AI agent connected via MCP (or an attacker influencing that agent through prompt injection) can read any file on the host and exfiltrate it by uploading it as a Confluence page attachment.

Vulnerable Code

File: src/mcp_atlassian/confluence/attachments.py, lines 62-79

# No validate_safe_path() call anywhere in this method
if not os.path.isabs(file_path):
    file_path = os.path.abspath(file_path)

if not os.path.exists(file_path):
    return {"success": False, "error": f"File not found: {file_path}"}

filename = os.path.basename(file_path)
attachment = self._upload_attachment_direct(
    content_id, file_path, filename, comment, minor_edit
)

The validate_safe_path function is already imported at line 9 of the same file, and used in the download methods. It was just not added to the upload path.

Proof of Concept

Tested with mcp-atlassian 0.21.1 on Python 3.11 (EC2, Amazon Linux 2023).

import inspect
from mcp_atlassian.confluence.attachments import AttachmentsMixin

# Confirm: no validate_safe_path in upload
source = inspect.getsource(AttachmentsMixin.upload_attachment)
assert "validate_safe_path" not in source  # passes

# Confirm: validate_safe_path IS in downloads
assert "validate_safe_path" in inspect.getsource(AttachmentsMixin.download_attachment)  # passes
assert "validate_safe_path" in inspect.getsource(AttachmentsMixin.download_content_attachments)  # passes

An MCP tool call like this reads /etc/passwd and uploads it to Confluence:

{"tool": "confluence_upload_attachment", "arguments": {"content_id": "123456", "file_path": "/etc/passwd"}}

Impact

Exfiltration of any file readable by the MCP server process: SSH keys, AWS credentials, .env files, /etc/passwd, application secrets. Data leaves the local machine and lands on a remote Confluence instance accessible to other users.

Suggested Fix

Add validate_safe_path(file_path) before the os.path.exists() check in upload_attachment, matching the existing pattern in the download methods. The function is already imported.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "PyPI",
        "name": "mcp-atlassian"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.22.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-77258"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-22"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-22T20:36:37Z",
    "nvd_published_at": "2026-09-22T18:17:18Z",
    "severity": "HIGH"
  },
  "details": "## Summary\n\nThe `upload_attachment` method in `confluence/attachments.py` reads and uploads arbitrary local files to Confluence without calling `validate_safe_path()`. Both download methods (`download_attachment` at line 223, `download_content_attachments` at line 272) correctly call `validate_safe_path()` before writing files, but the upload path at lines 35-79 skips this check entirely.\n\nAn AI agent connected via MCP (or an attacker influencing that agent through prompt injection) can read any file on the host and exfiltrate it by uploading it as a Confluence page attachment.\n\n## Vulnerable Code\n\nFile: `src/mcp_atlassian/confluence/attachments.py`, lines 62-79\n\n```python\n# No validate_safe_path() call anywhere in this method\nif not os.path.isabs(file_path):\n    file_path = os.path.abspath(file_path)\n\nif not os.path.exists(file_path):\n    return {\"success\": False, \"error\": f\"File not found: {file_path}\"}\n\nfilename = os.path.basename(file_path)\nattachment = self._upload_attachment_direct(\n    content_id, file_path, filename, comment, minor_edit\n)\n```\n\nThe `validate_safe_path` function is already imported at line 9 of the same file, and used in the download methods. It was just not added to the upload path.\n\n## Proof of Concept\n\nTested with mcp-atlassian 0.21.1 on Python 3.11 (EC2, Amazon Linux 2023).\n\n```python\nimport inspect\nfrom mcp_atlassian.confluence.attachments import AttachmentsMixin\n\n# Confirm: no validate_safe_path in upload\nsource = inspect.getsource(AttachmentsMixin.upload_attachment)\nassert \"validate_safe_path\" not in source  # passes\n\n# Confirm: validate_safe_path IS in downloads\nassert \"validate_safe_path\" in inspect.getsource(AttachmentsMixin.download_attachment)  # passes\nassert \"validate_safe_path\" in inspect.getsource(AttachmentsMixin.download_content_attachments)  # passes\n```\n\nAn MCP tool call like this reads /etc/passwd and uploads it to Confluence:\n\n```json\n{\"tool\": \"confluence_upload_attachment\", \"arguments\": {\"content_id\": \"123456\", \"file_path\": \"/etc/passwd\"}}\n```\n\n## Impact\n\nExfiltration of any file readable by the MCP server process: SSH keys, AWS credentials, .env files, /etc/passwd, application secrets. Data leaves the local machine and lands on a remote Confluence instance accessible to other users.\n\n## Suggested Fix\n\nAdd `validate_safe_path(file_path)` before the `os.path.exists()` check in `upload_attachment`, matching the existing pattern in the download methods. The function is already imported.",
  "id": "GHSA-93xw-j965-9mx3",
  "modified": "2026-09-22T20:36:37Z",
  "published": "2026-09-22T20:36:37Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/sooperset/mcp-atlassian/security/advisories/GHSA-93xw-j965-9mx3"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-77258"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sooperset/mcp-atlassian/pull/1448"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sooperset/mcp-atlassian/commit/b041733473f95119dd539542a43c280737a8e460"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sooperset/mcp-atlassian"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sooperset/mcp-atlassian/releases/tag/v0.22.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N",
      "type": "CVSS_V3"
    }
  ],
  "summary": "MCP Atlassian: Arbitrary file read/exfiltration via upload_attachment missing validate_safe_path()"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…