VAITP Dataset

← Back to the dataset

CVE-2026-44336

Path traversal in PraisonAI's MCP server allows file write and code execution.

  • CVSS 9.4
  • CWE-20
  • Input Validation and Sanitization
  • Remote

PraisonAI is a multi-agent teams system. Prior to version 4.6.34, PraisonAI's MCP (Model Context Protocol) server (praisonai mcp serve) registers four file-handling tools by default — praisonai.rules.create, praisonai.rules.show, praisonai.rules.delete, and praisonai.workflow.show. Each accepts a path or filename string from MCP tools/call arguments and joins it onto ~/.praison/rules/ (or, for workflow.show, accepts an absolute path) with no containment check. The JSON-RPC dispatcher passes params["arguments"] blind to each handler via **kwargs without validating against the advertised input schema. By setting rule_name="../../<some-path>" an attacker walks out of the rules directory and writes any file the running user can write. Dropping a Python .pth file into the user site-packages directory escalates this primitive to arbitrary code execution in any subsequent Python process the user spawns — the next praisonai CLI invocation, an IDE script run, the user's python REPL, or any background Python service. This issue has been patched in version 4.6.34.

CVSS base score
9.4
Published
2026-05-08
OWASP
A08 Software and Data Integrity Failures
Orthogonal defect classification
Checking
Code defect classification
Missing Check
Category
Input Validation and Sanitization
Subcategory
Path Traversal
Accessibility scope
Remote
Impact
Arbitrary Code Execution
Affected component
PraisonAI
Fixed by upgrading
Yes

Solution

Upgrade PraisonAI to version 4.6.34 or later.

Vulnerable code sample

import os

# This code represents a simplified version of the vulnerable 'praisonai.rules.create'
# tool handler in PraisonAI before version 4.6.34, as described in CVE-2026-44336.
#
# The server's dispatcher would receive a remote call and pass the arguments
# (e.g., 'rule_name' and 'content') to a function like this one without
# proper validation or sanitization.

def create_rule_handler(rule_name: str, content: str, **kwargs):
    """
    A vulnerable function that creates a rule file.

    This function is vulnerable to path traversal because it joins a base
    directory with a user-provided 'rule_name' without checking for
    directory traversal characters like '..'. An attacker can exploit this
    to write a file to an arbitrary location on the filesystem, leading to
    potential remote code execution.
    """
    # In the actual application, this base path points to ~/.praison/rules/
    base_directory = os.path.expanduser("~/.praison/rules/")

    # VULNERABLE CODE: The untrusted 'rule_name' is directly joined to the
    # base path. An attacker can provide a 'rule_name' like
    # "../../.local/lib/python3.10/site-packages/malicious_code.pth"
    # to escape the intended directory.
    file_path = os.path.join(base_directory, rule_name)

    # The directory for the path is created if it doesn't exist. This helps
    # the attacker by creating the directory structure for the malicious file.
    os.makedirs(os.path.dirname(file_path), exist_ok=True)

    # The file is written to the constructed path, which can be anywhere the
    # user running the server has write permissions.
    with open(file_path, "w") as f:
        f.write(content)

Patched code sample

import os
import pathlib

# In the actual application, this would be os.path.expanduser("~/.praison/rules")
# For this example, we use a local directory to represent the intended safe location.
BASE_RULES_DIR = pathlib.Path("./praison_rules").resolve()

def patched_create_rule(rule_name: str, content: str):
    """
    A simplified representation of the patched praisonai.rules.create function.
    
    This function demonstrates the fix for CVE-2026-44336 by ensuring
    the final file path is securely contained within the intended base directory.
    """
    if not rule_name or ".." in rule_name or "/" in rule_name:
        print(f"Error: Invalid characters in rule_name: '{rule_name}'")
        return

    # Construct the full path using the user-provided rule_name
    target_path = BASE_RULES_DIR / rule_name

    # --- THE FIX ---
    # 1. Resolve the path to its absolute, canonical form. This collapses
    #    any '..' sequences or symbolic links that might have bypassed the simple check.
    resolved_path = target_path.resolve()

    # 2. Check for path containment by verifying that the resolved path
    #    is a sub-path of the resolved base directory.
    #    The original code lacked this crucial check.
    try:
        resolved_path.relative_to(BASE_RULES_DIR)
    except ValueError:
        # This error is raised if `resolved_path` is not within `BASE_RULES_DIR`.
        print(f"Error: Path traversal attempt detected for rule_name: '{rule_name}'")
        return
    # --- END OF FIX ---

    # If the containment check passes, proceed with the file operation.
    try:
        # Ensure the base directory exists before writing.
        os.makedirs(BASE_RULES_DIR, exist_ok=True)
        with open(resolved_path, "w") as f:
            f.write(content)
        print(f"Success: Rule safely created at {resolved_path}")
    except IOError as e:
        print(f"Error: Could not write to file. {e}")

Payload

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "name": "praisonai.rules.create",
    "arguments": {
      "rule_name": "../../.local/lib/python3.11/site-packages/exploit.pth",
      "content": "import os; os.system('touch /tmp/pwned')"
    }
  },
  "id": 1
}

Cite this entry

@misc{vaitp:cve202644336,
  title        = {{Path traversal in PraisonAI's MCP server allows file write and code execution.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-44336},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-44336/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::