Описание
PraisonAI: Coarse-Grained Tool Approval Cache Bypasses Per-Invocation Consent for Shell Commands
Summary
The approval system in PraisonAI Agents caches tool approval decisions by tool name only, not by invocation arguments. Once a user approves execute_command for any command (e.g., ls -la), all subsequent execute_command calls in that execution context bypass the approval prompt entirely. Combined with os.environ.copy() passing all process environment variables to subprocesses, this allows an LLM agent (potentially via prompt injection) to silently exfiltrate API keys and credentials without further user consent.
Details
The require_approval decorator in src/praisonai-agents/praisonaiagents/approval/__init__.py:176-178 checks approval status by tool name only:
The mark_approved function in registry.py:144-147 stores only the tool name string:
The approval context is never cleared during agent execution — clear_approved() exists (registry.py:152) but is never called in the agent's tool execution path (agent/tool_execution.py).
Meanwhile, the ConsoleBackend UI at backends.py:95-96 misleads the user:
The UI displays the specific command arguments (lines 81-85), creating a reasonable expectation that the user is approving only that specific invocation.
Additionally, shell_tools.py:77 passes the full process environment to every subprocess:
There is no command filtering, blocklist, or environment variable sanitization in the shell tools module.
PoC
Impact
- Secret exfiltration: An LLM agent (or one subjected to prompt injection) can dump all process environment variables after a single benign command approval. Common secrets include
OPENAI_API_KEY,AWS_SECRET_ACCESS_KEY,DATABASE_URL, and any other credentials passed via environment. - Misleading consent UI: The console prompt displays specific arguments and uses language ("this tool") that implies per-invocation consent, but the system grants session-wide blanket approval.
- No expiration or scope: The approval cache uses a
ContextVarthat persists for the entire agent execution context with no timeout, no command-count limit, and no clearing between tool calls. - No environment filtering:
os.environ.copy()passes every environment variable to subprocesses without filtering sensitive patterns.
Recommended Fix
- Per-invocation approval for critical tools — store a hash of
(tool_name, arguments)instead of justtool_name, or require re-approval for each invocation of critical-risk tools:
- Filter environment variables in
shell_tools.py:
Пакеты
praisonaiagents
< 4.5.128
4.5.128
Связанные уязвимости
PraisonAI before 1.5.128 caches tool approval decisions by tool name only, not by invocation arguments, allowing subsequent execute_command calls to bypass approval prompts. Attackers can exploit this by obtaining initial approval for a benign command, then silently exfiltrate API keys and credentials via subsequent shell commands without user consent.