Vulnerability GHSA-5rmq-chc7-m22f

High Risk
HIGH RISK
CVSS Score: 7.5
Score Range: 7.0–8.9
High severity vulnerabilities (CVSS 7.0–8.9). Serious vulnerabilities that should be prioritized soon after critical fixes.
18 days ago
October 02, 2026 at 10:44 PM UTC
Vibe-Trading file-read tools expose arbitrary server-readable files
0.1.0 - 0.1.6
0.1.0 - 0.1.6

Summary

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

Details

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.

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.

Why F9 and F10 are listed separately

A maintainer might be tempted to fix only one, on the theory that F10 dominates F9. Two reasons to fix both:

  1. Different fix scope — F10's fix is a single missing call (safe_path(file_path) in read_document before line 270). F9's fix is in safe_user_path() itself: the envelope must be replaced with a strict allowlist of operator-configured directories, not Path.home() ∪ Path.cwd(). A fix that adds the missing safe_user_path call to read_document is insufficient because safe_user_path itself accepts /root and /app/agent/.env. Both surfaces need work.

  2. Different reachability classes — F9 is reachable through tools that already gate on safe_user_path (ExtractShadowStrategyTool and several journal tools), so even a hypothetical F10 fix that switched read_document to use safe_user_path would still leak /root/* because the envelope is broken. F9 is the structural defect; F10 is the missed call.

Impacted packages

Timeline

Published
18 days ago
October 02, 2026 at 10:44 PM UTC
Fixed (0.1.7)
5 months ago
May 06, 2026 at 12:09 PM UTC
Last Modified
1 hour ago
October 21, 2026 at 10:57 AM UTC