GitHub Security Advisory: GHSA-2hch-c97c-g99x
Package: wwbn/avideo (COMPOSER)
Severity: HIGH (CVSS 7.7)
CWE: CWE-918: Server-Side Request Forgery (SSRF)
Vulnerable versions: <= 29.0
Patched in: unpatched

Summary: AVideo has SSRF Protection Bypass via HTTP Redirect and DNS Rebinding in isSSRFSafeURL()

Details:
### Summary

Two endpoints in AVideo call `isSSRFSafeURL()` to validate user-supplied URLs, then fetch them using bare `file_get_contents()` **without disabling PHP's automatic redirect following**. An attacker can supply a URL pointing to a server they control that returns a 302 redirect to an internal/cloud-metadata address (e.g., `http://169.254.169.254/latest/meta-data/`). Since `isSSRFSafeURL()` only validates the *initial* URL, the redirect target bypasses all SSRF protections.

A secondary finding is that 6+ callers of `isSSRFSafeURL()` discard the `$resolvedIP` out-parameter meant for DNS pinning, leaving them vulnerable to DNS rebinding TOCTOU attacks.

**Severity:** High — CVSS 3.1: 7.7 (AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:N/A:N)

### Details

#### Finding 1: Redirect-Based SSRF Bypass

**Vulnerable code — `plugin/AI/receiveAsync.json.php` (line ~162–165):**

```php
// SSRF Protection: Validate URL before fetching
if (!isSSRFSafeURL($imageUrl)) {
    // blocked
} else {
    $imageContent = file_get_contents($imageUrl);  // ← FOLLOWS REDIRECTS!
}
```

**Vulnerable code — `objects/EpgParser.php` (line ~358–362):**

```php
if (!isSSRFSafeURL($this->url)) {
    throw new \RuntimeException('URL blocked by SSRF protection');
}
$this->content = @file_get_contents($this->url);  // ← FOLLOWS REDIRECTS!
```

**Safe code for comparison — `objects/functions.php`, `url_get_contents()`:**

```php
$opts = ['http' => ['follow_location' => 0]];  // Disable auto-redirect
$context = stream_context_create($opts);
for ($redirectCount = 0; $redirectCount <= 5; $redirectCount++) {
    $fetched = file_get_contents($currentUrl, false, $context);
    // ... parse Location header ...
    if ($redirectTarget) {
        if (!isSSRFSafeURL($redirectTarget)) {  // Re-validates EACH hop
            return false;
        }
        $currentUrl = $redirectTarget;
        continue;
    }
    $tmp = $fetched;
    break;
}
```

**Root cause:** The SSRF redirect protection (`follow_location=0` + manual redirect loop with per-hop `isSSRFSafeURL()` re-validation) was correctly implemented in `url_get_contents()` but NOT propagated to these two endpoints that call `file_get_contents()` directly. PHP's default `follow_location` is `1` (follow redirects).

#### Finding 2: DNS Rebinding TOCTOU (Multiple Callers)

`isSSRFSafeURL()` provides a `$resolvedIP` out-parameter for DNS pinning via `CURLOPT_RESOLVE`. Only 1 of 9 callers (`plugin/LiveLinks/proxy.php`) uses it. The remaining 8 callers discard it and pass the original hostname to the fetching function, which resolves DNS independently — creating a TOCTOU race window exploitable via DNS rebinding (TTL=0).

**Affected callers (no DNS pinning):**
- `objects/aVideoEncoderReceiveImage.json.php` — 4 call sites
- `objects/aVideoEncoder.json.php` — 1 call site
- `plugin/BulkEmbed/save.json.php` — 1 call site
- `plugin/AI/receiveAsync.json.php` — 1 call site
- `objects/EpgParser.php` — 1 call site
- `plugin/Scheduler/Scheduler.php` — 1 call