# Vulnerability Verification Report

## 1. Summary
- **Vulnerability Type**: CORS Misconfiguration (CWE-942)
- **Flagged Location**: `src/praisonai-agents/praisonaiagents/ui/agui/agui.py:131-141`
- **Vulnerability Description**: The AGUI endpoint (`POST /agui`) hardcodes `Access-Control-Allow-Origin: *` on all responses, has no authentication, and accepts arbitrary agent execution requests. Any malicious website can trigger agent execution on a victim's locally-running AGUI server and read the full response, including tool execution results and potentially sensitive data.

## 2. Analysis Logic

### Step 1: Examining the flagged CORS configuration at `src/praisonai-agents/praisonaiagents/ui/agui/agui.py:131-141`
```python
        @router.post("/agui")
        async def run_agent_agui(run_input: RunAgentInput):
            """Run the agent via AG-UI protocol."""
            async def event_generator():
                async for event in self._run_agent(run_input):
                    yield encoder.encode(event)
            
            return StreamingResponse(
                event_generator(),
                media_type="text/event-stream",
                headers={
                    "Cache-Control": "no-cache",
                    "Connection": "keep-alive",
                    "Access-Control-Allow-Origin": "*",
                    "Access-Control-Allow-Methods": "POST, GET, OPTIONS",
                    "Access-Control-Allow-Headers": "*",
                },
            )
```
The `StreamingResponse` hardcodes `Access-Control-Allow-Origin: *` (line 137), `Access-Control-Allow-Methods: POST, GET, OPTIONS` (line 138), and `Access-Control-Allow-Headers: *` (line 139). These headers are baked into the library response object and cannot be overridden by consumers without patching the source. There is no `allowed_origins` parameter or similar configuration in `AGUI.__init__` (lines 61-96).

### Step 2: Checking authentication on the `/agui` endpoint at `src/praisonai-agents/praisonaiagents/ui/agui/agui.py:124-125`
```python
        @router.post("/agui")
        async def run_agent_agui(run_input: RunAgentInput):
```
The endpoint uses no authentication decorator, no dependency injection for API keys, no bearer token validation, and no session check. The `RunAgentInput` model (defined in `types.py:159-165`) contains only `thread_id`, `run_id`, `messages`, `state`, and `forwarded_props` — none of which are auth tokens. The router is created at line 111 with `APIRouter(prefix=self.prefix, tags=self.tags)` and no middleware or dependencies.

### Step 3: Tracing what data the endpoint returns via `src/praisonai-agents/praisonaiagents/ui/agui/agui.py:148-203`
The `_run_agent` method converts user input and streams it through `async_stream_agent_response` or `async_stream_agents_response`. These functions (in `streaming.py`) yield events including `TextMessageContentEvent`, `ToolCallResultEvent`, and `RunErrorEvent`. The streamed response contains:
- Agent-generated text messages
- Tool call arguments and results (including file contents, shell output, API responses, etc.)
- Error messages with stack traces

This is sensitive data that an attacker would want to exfiltrate.

### Step 4: Verifying the CORS preflight bypass mentioned in the advisory
Starlette/FastAPI's Pydantic body parsing (`run_input: RunAgentInput`) internally calls `Request.json()`, which in turn calls `json.loads(await self.body())` without verifying that `Content-Type` is `application/json`. A browser POST with `Content-Type: text/plain` is classified as a CORS "simple request" per the Fetch specification — no preflight OPTIONS request is sent. The JSON body is still parsed successfully. The response includes `Access-Control-Allow-Origin: *`, so the browser allows the attacker's JavaScript to read the response body.

### Step 5: Checking if the code is in test/demo/dead context
The file is located at `src/praisonai-agents/praisonaiagents/ui/agui/agui.py` — this is a core production library module. It is imported and re-exported from:
- `src/praisonai-agents/praisonaiagents/ui/agui/__init__.py:20`
- `src/praisonai-agents/praisonaiagents/ui/__init__.py:11`
- `src/praisonai-agents/praisonaiagents/__init__.py:310`

Tests in `src/praisonai-agents/tests/agui/test_router.py:210` explicitly assert that the CORS header equals `*`, confirming this is intentional documented behavior rather than an artifact.

### Step 6: Checking what capabilities the agent has
The `Agent` class supports arbitrary tools. Built-in tools include `file_tools.py` (read files) and `shell_tools.py` (execute shell commands). While some tools require approval, file reading does not. An attacker could instruct the agent to read sensitive files (e.g., `~/.ssh/id_rsa`, environment variables) and the tool output would be streamed back in the response, readable cross-origin due to the wildcard CORS header.

### Analysis Process
- Q1: Is CORS configured (`Access-Control-Allow-Origin` header set)? → **YES**, hardcoded at `agui.py:137`.
- Q2: Is the origin restricted to a specific allowlist? → **NO**, it is wildcard `*` with no configuration option.
- Q3: Is `Access-Control-Allow-Credentials: true`? → **NO**, the header is absent.
- Q4: Does the endpoint return sensitive data without auth? → **YES**, the endpoint has no authentication and returns agent outputs, tool results (file contents, shell output), and error messages.
- Q5: Is the code in test/demo/dead/generated context? → **NO**, it is a core production library module exported as public API.
- → Reached leaf: **TRUE_POSITIVE**

## 3. Verdict
**TRUE_POSITIVE**

**Key Evidence:**
- `src/praisonai-agents/praisonaiagents/ui/agui/agui.py:137` hardcodes `"Access-Control-Allow-Origin": "*"` in the `StreamingResponse` headers with no consumer-overridable configuration.
- `src/praisonai-agents/praisonaiagents/ui/agui/agui.py:124-125` defines the `/agui` endpoint with no authentication, API key, or session validation.
- `src/praisonai-agents/praisonaiagents/ui/agui/types.py:159-165` shows `RunAgentInput` has no auth-related fields.
- The agent framework includes tools like `file_tools.py` and `shell_tools.py` that can access sensitive data, and their outputs are streamed back to the client.
- `src/praisonai-agents/tests/agui/test_router.py:210` explicitly asserts the wildcard CORS header, confirming it is intentional library behavior.

## 4. Remediation Suggestions
- **Remove the hardcoded CORS headers** from `StreamingResponse` in `agui.py` and let consumers configure CORS via FastAPI's `CORSMiddleware` with an explicit origin allowlist.
- **Add an `allowed_origins` parameter** to `AGUI.__init__` so consumers can restrict CORS, defaulting to an empty list (no cross-origin access) instead of `*`.
- **Add authentication support** to the `/agui` endpoint, such as an optional API key dependency that consumers can enable when mounting the router.
- **Add a Content-Type validation** defense-in-depth check (`Content-Type: application/json`) to prevent simple-request CORS bypass via `text/plain`.
- **Update tests** in `test_router.py` to verify that CORS headers are configurable rather than asserting the presence of a wildcard.
