Skip to content

mail-mcp-bridge Path Traversal / Arbitrary Directory Deletion Vulnerability #60

Description

@wing3e

mail-mcp-bridge Path Traversal / Arbitrary Directory Deletion Vulnerability Report

1) CNA / Submission Type

  • Submission type: Report a vulnerability (CVE ID request)
  • Reporter role: Independent security researcher
  • Report date: April 10, 2026

2) Reporter Contact (fill before submit)

  • Reporter name: Winegee
  • Reporter email: Winegee@zju.edu.cn
  • Permission to share contact with vendor: Yes

3) Vendor / Product Identification

  • Vendor: fatbobman
  • Product: mail-mcp-bridge
  • Repository: https://github.com/fatbobman/mail-mcp-bridge.git
  • Reviewed local source path: python-batch-04/datasets/fatbobman-mail-mcp-bridge
  • Affected component(s):
  • src/mail_mcp_server.py
  • src/cleanup_attachments.py
  • src/extract_attachments.py

4) Vulnerability Type

  • CWE: CWE-22 / CWE-73 (Path Traversal / External Control of File Name or Path)
  • Short title: path traversal in cleanup_attachments allows deletion of directories outside the attachment cache root

5) Affected Versions

  • Confirmed affected: d9e7d9acc2abcf9da8252d76506fc5afbc08d08e
  • Suspected affected range: revisions containing the same message_ids path-join behavior documented below
  • Fixed version: Not available at time of report (April 10, 2026)

6) Vulnerability Description

The cleanup_attachments MCP tool accepts a list of RFC message_ids and is intended to remove temporary extraction directories beneath the attachment cache root. However, the implementation only strips angle brackets from each message_id before joining it under the base directory. Traversal sequences such as ../mail-mcp-bridge-poc survive unchanged, so the server resolves a path outside mail-mcp-attachments and recursively deletes it with shutil.rmtree(). This provides a real arbitrary-directory deletion primitive relative to the temp root used by the service. The related extraction flow in extract_attachments.py repeats the same unsafe message_id-to-directory join when creating directories.

7) Technical Root Cause

  1. The server exposes a cleanup tool that forwards caller-controlled message_ids into the cleanup helper:
    • src/mail_mcp_server.py:151-165
    • src/mail_mcp_server.py:430-441
  2. The attachment base path defaults to /tmp/mail-mcp-attachments (or ${MAIL_ATTACHMENT_PATH}/mail-mcp-attachments):
    • src/cleanup_attachments.py:13-24
  3. Each attacker-controlled message_id is only normalized with strip('<>'), which does not remove ../ traversal tokens:
    • src/cleanup_attachments.py:67-70
    • Code: clean_message_id = message_id.strip('<>')
  4. The code then enumerates and recursively deletes the resulting path without a containment check:
    • src/cleanup_attachments.py:72-84
    • Code: shutil.rmtree(message_dir)
  5. The extraction helper contains the same root cause on directory creation:
    • src/extract_attachments.py:131-135
    • Code: message_dir = Path(base_dir) / clean_message_id
    • In this repository, the cleanup path is the strongest exploit primitive because it does not depend on a valid Mail message or attachment payload.

8) Attack Prerequisites

  • Ability to invoke the cleanup_attachments MCP tool.
  • The server must run with filesystem permissions to access and remove the targeted directory.
  • A deployment where untrusted or partially trusted callers can submit arbitrary message_ids.
  • For the demonstrated PoC, the chosen victim directory must exist as a sibling reachable through ../ from the configured attachment base path.

9) Proof of Concept / Reproduction Guidance

This PoC exercises the real vulnerable deletion path without depending on a valid macOS Mail message.

  1. Ensure the server uses the default temp base or set:
export MAIL_ATTACHMENT_PATH=/tmp
  1. Create a harmless sibling directory outside the intended cache root:
mkdir -p /tmp/mail-mcp-bridge-poc
printf 'sentinel\n' > /tmp/mail-mcp-bridge-poc/evidence.txt
  1. Send the following MCP tool call:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "cleanup_attachments",
    "arguments": {
      "message_ids": [
        "../mail-mcp-bridge-poc"
      ]
    }
  }
}
  1. Expected result:
  • The helper computes message_dir = Path("/tmp/mail-mcp-attachments") / "../mail-mcp-bridge-poc".
  • message_dir.exists() succeeds because the path resolves to /tmp/mail-mcp-bridge-poc.
  • shutil.rmtree(message_dir) deletes the sibling directory outside mail-mcp-attachments.
  • The JSON response reports the cleaned path as something like /tmp/mail-mcp-attachments/../mail-mcp-bridge-poc, and /tmp/mail-mcp-bridge-poc/evidence.txt is gone afterward.

10) Security Impact

  • Confidentiality: Low. The cleanup code enumerates files and sizes inside attacker-selected directories before deletion.
  • Integrity: High. Attackers can delete directories outside the intended attachment cache root.
  • Availability: High. Deleting application data or operator-owned temp directories can disrupt the host or nearby services.
  • Scope: Unchanged.

11) CVSS v3.1 Suggestion

  • Suggested vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:H
  • Suggested base score: 8.8 (High)
  • If only trusted authenticated operators can call the MCP tool, PR should be adjusted upward.

12) Workarounds / Mitigations

  • Reject message_id values containing path separators, traversal tokens, or absolute-path syntax before using them as directory names.
  • Resolve the candidate directory and verify that it remains under the canonical attachment base directory before any exists(), rglob(), or rmtree() call.
  • Consider using a server-generated opaque directory name instead of mapping raw RFC Message-ID values directly onto the filesystem.
  • Restrict access to attachment-management tools until a fix is deployed.

13) Recommended Fix

  • Apply canonicalization plus root-boundary enforcement in both cleanup_attachments.py and extract_attachments.py.
  • Treat message_id as untrusted input even if it resembles a mail header value; remove path separators rather than only stripping angle brackets.
  • Add regression tests for payloads such as ../mail-mcp-bridge-poc, ..\\mail-mcp-bridge-poc, absolute paths, and symlink-based escapes.
  • Return an explicit error when the resolved path is outside the attachment cache root.

14) References

15) Credits

  • Discoverer: Winegee
  • Discovery method: Static analysis (CodeQL) plus repository source-code audit

16) Additional Notes for Form Mapping

  • Audit verdict: Confirmed vulnerability.
  • Total reviewed SARIF results for this rule in the repository: 5
  • Concrete PoC status: source-confirmed and mapped to the real cleanup_attachments tool and deletion sink.
  • Dynamic exploit replay status: not executed end-to-end in this batch update.
  • Version-range accuracy should be finalized by the maintainer against release history before public disclosure.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions