GitHub Security Advisory: GHSA-9x67-f2v7-63rw
Package: wwbn/avideo (COMPOSER)
Severity: HIGH (CVSS 8.6)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: <= 25.0
Patched in: unpatched

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

Details:
## Summary
The `plugin/LiveLinks/proxy.php` endpoint validates user-supplied URLs against internal/private networks using `isSSRFSafeURL()`, but only checks the initial URL. When the initial URL responds with an HTTP redirect (`Location` header), the redirect target is fetched via `fakeBrowser()` without re-validation, allowing an attacker to reach internal services (cloud metadata, RFC1918 addresses) through an attacker-controlled redirect.

## Affected Component
- `plugin/LiveLinks/proxy.php` — lines 38-42 (redirect handling without SSRF re-validation)
- `objects/functionsBrowser.php` — `fakeBrowser()` (line 123, raw cURL fetch with no SSRF protections)

## Description

### Missing SSRF re-validation after HTTP redirect

The `proxy.php` endpoint validates the user-supplied `livelink` parameter against internal networks on line 18, using the comprehensive `isSSRFSafeURL()` function (which blocks private IPs, loopback, link-local/metadata, cloud metadata hostnames, and resolves DNS to detect rebinding). However, after calling `get_headers()` on line 38 — which follows HTTP redirects — the code extracts the `Location` header and passes it directly to `fakeBrowser()` without re-applying the SSRF check:

```php
// plugin/LiveLinks/proxy.php — lines 17-42

// SSRF Protection: Block requests to internal/private networks
if (!isSSRFSafeURL($_GET['livelink'])) {                    // line 18: only checks initial URL
    _error_log("LiveLinks proxy: SSRF protection blocked URL: " . $_GET['livelink']);
    echo "Access denied: URL targets restricted network";
    exit;
}

// ... stream context setup ...

$headers = get_headers($_GET['livelink'], 1, $context);      // line 38: follows redirects
if (!empty($headers["Location"])) {
    $_GET['livelink'] = $headers["Location"];                 // line 40: attacker-controlled redirect target
    $urlinfo = parse_url($_GET['livelink']);
    $content = fakeBrowser($_GET['livelink']);                 // line 42: fetches internal URL, NO SSRF check
    $_GET['livelink'] = "{$urlinfo["scheme"]}://{$urlinfo["host"]}:{$urlinfo["port"]}";
}
```

### No SSRF protections in fakeBrowser()

The `fakeBrowser()` function in `objects/functionsBrowser.php` performs a raw cURL GET with no URL validation:

```php
// objects/functionsBrowser.php — lines 123-141
function fakeBrowser($url)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 ...');
    $output = curl_exec($ch);
    curl_close($ch);
    return $output;
}
```

No IP validation, no scheme restriction, no redirect control — any URL passed to this function is fetched unconditionally.

### Endpoint is fully unauthenticated

The file begins by explicitly opting out of database and session initialization:

```php
$doNotConnectDatabaseIncludeConfig = 1;
$doNotStartSessionbaseIncludeConfig = 1;
require_once '../../videos/configuration.php';
```

There is no `.h