# PraisonAI: [Path Traversal] agent tools escape the configured workspace via symlinks

PraisonAI agent code tools enforce workspace containment with abspath instead of realpath, so in-workspace symlinks, unchecked list_files, and unvalidated execute_command cwd escape the workspace.

- Payout: Research
- Severity: high
- Program: PraisonAI
- Found by: riodrwn
- Disclosed: 2026-08-25
- CVE: CVE-2026-55540
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-ch89-h4r2-c8f8
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-ch89-h4r2-c8f8
- Tags: area:ai domain:ai domain:oss impact:data-leak impact:integrity kind:research platform:ghsa sev:high tech:python technique:source-review vuln:access-control vuln:command-injection vuln:path-traversal

**Target:** Python agent code tool wrappers (read_file, write_file, apply_diff, search_replace, list_files, execute_command)
**Root cause:** is_path_within_directory() uses os.path.abspath() which does not canonicalize symlinks, so in-workspace links to outside targets pass; list_files() and execute_command() cwd never call the containment helper at all.
**Steps:**
1. Create workspace and outside dirs; place secret.txt in outside.
2. Baseline: `read_file('../outside/secret.txt')` returns "Path '../outside/secret.txt' is outside the workspace" (blocked).
3. Create symlink inside workspace: `WORKSPACE/link_to_secret.txt` -> `/outside/secret.txt`; `read_file('link_to_secret.txt')` returns SECRET_OUTSIDE_WORKSPACE.
4. Symlink write: write_file through the in-workspace link overwrites the outside file with OVERWRITTEN_VIA_SYMLINK.
5. `code_list_files('../outside')` lists outside directory contents (no containment check).
6. `code_execute_command(cwd='../outside', 'pwd')` returns the outside path; running `python3 -c open('planted.txt','w')...` creates a file outside the workspace.
**How found:** Reporter read the source and noticed the module asserts a workspace security boundary in comments and docstrings, then compared the containment helper's abspath() against realpath() semantics and audited each tool for whether it actually calls the helper — finding list_files and execute_command cwd skip it entirely.
**Exploitation:** An attacker who can influence an agent with these tools attached (untrusted prompt, indirect prompt injection, or server-exposed agent) supplies a symlink path or ../ cwd; the tools follow the link or run from the escaped directory, reading/overwriting/listing/executing outside the workspace, bounded only by the process user's filesystem permissions.
**Escalation:** Chaining read/write/list/execute primitives across the boundary lets an attacker exfiltrate secrets and plant files outside the project, then run binaries from the escaped cwd.
**Insight:** When a codebase advertises a path-containment boundary, grep for the helper's call sites and check the canonicalization primitive: abspath/startswith is symlink-bypassable, and any tool taking a path or cwd that doesn't call the helper is a direct escape.

