Summary
PraisonAI's workflow include implementation implicitly imports and executes an included recipe's tools.py file even when the documented tools.py autoload opt-in is unset.
This bypasses the hardening added for the prior automatic tools.py RCE advisory family. A workflow that includes an untrusted local recipe can execute arbitrary Python module-level code before any model call or child workflow execution.
The same sink is reachable through the higher-level praisonai.recipe.run() recipe API when a steps-based recipe workflow includes a local child recipe. The supplementary PoV demonstrates this route without starting a network service or relying on external APIs.
This is distinct from the previously published tool_resolver.py, api/call.py, templates/tool_override.py, and agents_generator.py variants. The affected callsite is the workflow include implementation in praisonaiagents, reached through the documented/covered Include workflow composition feature.
Affected Components
- Package:
praisonaiagents
- File:
praisonaiagents/workflows/workflows.py
- Sink:
Workflow._execute_include()
- Current affected callsite:
tools_py = recipe_path / "tools.py"
if tools_py.exists():
spec = importlib.util.spec_from_file_location("recipe_tools", tools_py)
recipe_module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(recipe_module)
The current head also contains a similar unguarded workflow-local tools.py import in _resolve_pydantic_class(). That adjacent sink is not needed for the primary impact claim because the include path has a cleaner public workflow execution path and local PoV.
Security Boundary
PraisonAI documents secure defaults for implicit tools.py autoload: