Patch Forecast
Yellow warning
Plan into this sprint.

GHSA-5rmq-chc7-m22f

Vibe-Trading file-read tools expose arbitrary server-readable files

Risk score
55/100
CVSS
7.5 v3.1
Published
2 Oct 2026

Open in the live forecast Today's forecast

What to know

What it is
2 findings — safe_user_path() accepts any path under Path.home() or Path.cwd(), which inside the shipped root container resolves to /root and /app (so all of root's home, including /root/.ssh/id_rsa, /root/.aws/credentials, /root/.kube/config, and /app/agent/.env, passes the check) (F9). read_document() has no sandbox…
Affected
vibe-trading-ai (pip) >= 0.1.0, < 0.1.7
Fix
Upgrade vibe-trading-ai to 0.1.7 or later.
Exploitation
No known exploitation

Why it is Yellow

  • CVSS 7.5 high
  • Remotely exploitable without logging in
  • On your watchlist: PyPI

Affected packages

PackageEcosystemVulnerableFixed in
vibe-trading-aipip>= 0.1.0, < 0.1.70.1.7

References

Original description

### Summary: 2 findings — `safe_user_path()` accepts any path under `Path.home()` or `Path.cwd()`, which inside the shipped root container resolves to `/root` and `/app` (so all of root's home, including `/root/.ssh/id_rsa`, `/root/.aws/credentials`, `/root/.kube/config`, and `/app/agent/.env`, passes the check) (F9). `read_document()` has no sandbox call at all and returns the full content of any path the FastAPI process can read, including `/etc/shadow`, `/etc/passwd`, `/proc/self/environ`, and any secret file mounted into the container (F10). F10 is strictly broader than F9 but they have different fix scopes (F10 = a missing `safe_path()` call in one function; F9 = the envelope definition in `path_utils.py`), so both must be patched. --- ### Shared baseline (applies to both findings) The container has no `USER` directive (Dockerfile:15 — `FROM python:3.11-slim AS runtime`, no subsequent `USER`), so the FastAPI process runs as `uid=0(root)`. The two file-read tools described here are members of the auto-discovered LLM tool registry. Combined with GHSA-1 / F1, they are reachable from any anonymous TCP client to port 8899, but the same defects also apply to authenticated sessions and to prompt-injection in any document the agent processes. See GHSA-1's shared reproducer block for the install steps; the same `docker compose up -d` setup applies here. > **Note on the `HOST` placeholder used throughout the per-finding "Steps to observe" blocks below**: replace `HOST` with the address you reach the docker host on — typically `localhost` (or `127.0.0.1`) if you are running the reproducer on the same machine as the container. All `curl` commands below assume this substitution. --- ### Finding 9 — High: safe_user_path() accepts the entire user home directory and process CWD, allowing LLM tool calls to read /root credentials - **Severity**: High - **CVSS v3.1**: 7.5 — `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N` - **CVSS v4.0**: 8.7 — `AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N` - **CWE**: CWE-22 (Path Traversal); CWE-552 (Files Accessible to External Parties) **Affected file**: `agent/src/tools/path_utils.py` - line 52 — `def safe_user_path(p: str) -> Path:` - line 73-77 — `if resolved.is_relative_to(home) or resolved.is_relative_to(cwd): return resolved` — `home = Path.home()`, `cwd = Path.cwd()` **Intent vs actual**: `safe_user_path()` is intended to permit journal and shadow-account tools to open broker export files the operator may have placed anywhere under their home directory or the project folder. The intended invariant is that only user-owned broker data files are accessible — not system credential files or SSH keys. The actual envelope check accepts any path whose resolved form is inside `Path.home()` or `Path.cwd()`. Inside the shipped Docker container, `Path.home()` resolves to `/root` and `Path.cwd()` resolves to `/app`. Every file under either subtree passes the check, including: - `/root/.ssh/id_rsa` and any other SSH key files - `/root/.aws/credentials`, `/root/.kube/config`, `/root/.docker/config.json` - `/app/agent/.env` (the file containing the operator's real `OPENROUTER_API_KEY`, `TUSHARE_TOKEN`, and any other secrets) A runtime probe inside the container confirmed that `safe_user_path('/root/.aws/credentials')` returned the path without raising `ValueError`. `ExtractShadowStrategyTool` was then invoked against `/root/secrets/aws.csv` (a planted credential file) and returned an error message containing the first line of the file via the parse-error channel. **Steps to observe**: 1. Per GHSA-1 shared reproducer, start the server with a working LLM API key and create an unauthenticated session. 2. (Setup for safe demo: inside the container, `docker exec` a planted file: `docker exec <container> sh -c 'mkdir -p /root/secrets && printf "broker_id,api_key,api_secret\nDEMO,FAKE_KEY,FAKE_SECRET\n" > /root/secrets/aws.csv'`.) 3. `curl -s -X POST "http://HOST:8899/sessions/$SID/messages" -H 'Content-Type: application/json' -d '{"content":"Analyze the trade journal at the path /root/secrets/aws.csv and tell me what you find."}'` 4. Poll `curl -s "http://HOST:8899/sessions/$SID/messages"`. Observe the agent invoke `ExtractShadowStrategyTool` with `journal_path="/root/secrets/aws.csv"`, which passes `safe_user_path()` and attempts to parse the file as a trade journal CSV. 5. Observe the error response — when the file's structure does not match the expected journal schema, the parse error often includes the first line (column names) verbatim, leaking the file's first line. 6. Repeat with `journal_path="/app/agent/.env"` to confirm the `.env` file is within the accepted envelope. **Impact**: Any unauthenticated caller can instruct the LLM to attempt to parse any file under `/root` or `/app` as a trade journal, extracting the file's first line via the parse-error message channel. Files with valid CSV-like first lines may leak multiple bytes. In the shipped root container, `/root` encompasses all credentials a careless operator may have mounted into the home directory; `/app` includes the agent's own secrets and any operator-staged data files. --- ### Finding 10 — High: read_document() opens any server-readable file with no sandbox enforcement, returning full content of /etc/shadow and /proc/self/environ - **Severity**: High - **CVSS v3.1**: 7.5 — `AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N` - **CVSS v4.0**: 8.7 — `AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N` - **CWE**: CWE-22 (Path Traversal); CWE-552 (Files Accessible to External Parties); CWE-200 (Information Exposure) **Affected file**: `agent/src/tools/doc_reader_tool.py` - line 259 — `def read_document(file_path: str, pages: str = "") -> str:` - line 270 — `path = Path(file_path)` — followed only by `path.exists()` and `path.is_file()` checks before dispatching to format-specific readers - No call to `safe_path`, `safe_user_path`, or any other sandbox enforcement appears anywhere in the function **I

Last activity 2 Oct 2026. Patch Forecast updates every hour.