praisonaiagents resolves unresolved tool names against module globals and __main__ after it fails to match the declared tool list and the registry. With the default agent configuration, _perm_allow is None, so undeclared non-dangerous tool names are not rejected by the permission gate. An attacker who can influence tool-call names can therefore invoke unintended application callables that were never declared as tools.
The vulnerable resolution path is in [tool_execution.py](https://github.com/Users/shmulc/Documents/Codex/2026-05-03/please-go-over-tmp-tp-advisories/repos/PraisonAI/src/praisonai-agents/praisonaiagents/agent/tool_execution.py:734). After searching declared tools and the registry, execution falls back to globals() and then __main__:
func = None
for tool in self.tools if isinstance(self.tools, (list, tuple)) else []:
...
if func is None:
try:
from ..tools.registry import get_registry
registry = get_registry()
func = registry.get(function_name)
except ImportError:
pass
if func is None:
func = globals().get(function_name)
if not func:
import __main__
func = getattr(__main__, function_name, None)
If a callable is found, it is executed directly:
elif callable(func):
casted_arguments = self._cast_arguments(func, arguments)
return func(**casted_arguments)
The permission gate does not enforce a declared-tool allowlist by default. In...
4.6.371.6.37Exploitability
AV:NAC:LPR:NUI:NScope
S:UImpact
C:LI:HA:L8.6/CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:H/A:L