GitHub Security Advisory: GHSA-4wr3-f4p3-5wjh
Package: PraisonAI (PIP)
Severity: HIGH (CVSS 7.9)
CWE: CWE-306: Missing Authentication for Critical Function, CWE-396: Declaration of Catch for Generic Exception
Vulnerable versions: < 4.5.128
Patched in: 4.5.128

Summary: PraisonAI: Unauthenticated Allow-List Manipulation Bypasses Agent Tool Approval Safety Controls

Details:
## Summary

The gateway's `/api/approval/allow-list` endpoint permits unauthenticated modification of the tool approval allowlist when no `auth_token` is configured (the default). By adding dangerous tool names (e.g., `shell_exec`, `file_write`) to the allowlist, an attacker can cause the `ExecApprovalManager` to auto-approve all future agent invocations of those tools, bypassing the human-in-the-loop safety mechanism that the approval system is specifically designed to enforce.

## Details

The vulnerability arises from the interaction of three components:

**1. Authentication bypass in default config**

`_check_auth()` in `server.py:243-246` returns `None` (no error) when `self.config.auth_token` is falsy:

```python
# server.py:243-246
def _check_auth(request) -> Optional[JSONResponse]:
    if not self.config.auth_token:
        return None  # No auth configured → allow everything
```

`GatewayConfig` defaults `auth_token` to `None` (`config.py:61`):

```python
# config.py:61
auth_token: Optional[str] = None
```

**2. Unrestricted allowlist modification**

The `approval_allowlist` handler at `server.py:381-420` calls `_check_auth()` and proceeds when it returns `None`:

```python
# server.py:388-410
auth_err = _check_auth(request)
if auth_err:
    return auth_err
# ...
if request.method == "POST":
    _approval_mgr.allowlist.add(tool_name)  # No validation on tool_name
    return JSONResponse({"added": tool_name})
```

There is no validation that `tool_name` corresponds to a real tool, no restriction on which tools can be allowlisted, and no rate limiting.

**3. Auto-approval fast path**

When `GatewayApprovalBackend.request_approval()` is called by an agent (`gateway_approval.py:87`), it calls `ExecApprovalManager.register()`, which checks the allowlist first (`exec_approval.py:141-144`):

```python
# exec_approval.py:140-144
# Fast path: already permanently allowed
if tool_name in self.allowlist:
    future.set_result(Resolution(approved=True, reason="allow-always"))
    return ("auto", future)
```

The tool executes immediately without any human review.

**Complete data flow:**
1. Attacker POSTs `{"tool_name": "shell_exec"}` to `/api/approval/allow-list`
2. `_check_auth()` returns `None` (no auth token configured)
3. `_approval_mgr.allowlist.add("shell_exec")` adds to the `PermissionAllowlist` set
4. Agent later calls `shell_exec` → `GatewayApprovalBackend.request_approval()` → `ExecApprovalManager.register()`
5. `register()` hits the fast path: `"shell_exec" in self.allowlist` → `True`
6. Returns `Resolution(approved=True)` — no human review occurs
7. Agent executes the dangerous tool

## PoC

```bash
# Step 1: Verify the gateway is running with default config (no auth)
curl http://127.0.0.1:8765/health
# Response: {"status": "healthy", ...}

# Step 2: Check current allow-list (empty by default)
curl http://127.0.0.1:8765/api/approval/allow-list
# Response: {"allow_list": []}

# Step 3: Add dangerous tools to allow-list without authenticat