GHSA-9x67-f2v7-63rw AVideo vulnerable to unauthenticated SSRF via HTTP redirect bypass in LiveLinks proxy
SummaryThe `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)DescriptionMissing SSRF re-validation after HTTP redirectThe `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:No SSRF protections in fakeBrowser()The `fakeBrowser()` function in `objects/functionsBrowser.php` performs a raw cURL GET with no URL validation:No IP validation, no scheme restriction, no redirect control — any URL passed to this function is fetched unconditionally.Endpoint is fully unauthenticatedThe file begins by explicitly opting out of database and session initialization:There is no `.htaccess` rule restricting access to `proxy.php`, and the root `.htaccess` confirms the plugin directory is routable (line 248: `RewriteRule ^plugin/([^...]+)/(.*)?$ plugin/$1/$2`).Inconsistent defense patternThe codebase demonstrates awareness of SSRF risks — `isSSRFSafeURL()` is used in 5 other locations (`aVideoEncoder.json.php:303`, `aVideoEncoderReceiveImage.json.php:67,107,135,160`, `AI/receiveAsync.json.php:177`). However, none of these callers deal with HTTP redirects. The `proxy.php` endpoint is the only one that follows redirects, and it is the only one that fails to re-validate after following them.Double SSRF exposureThere are actually two SSRF requests in the redirect path:`get_headers()` (line 38) follows the redirect to the internal IP to fetch response headers`fakeBrowser()` (line 42) fetches the full response body from the internal IPThe second is more impactful as it returns the full content to the attacker.Proof of Concept**Step 1:** Set up an attacker-controlled server that returns a 302 redirect to an internal target:**Step 2:** Send the request to the target AVideo instance:**Expected result:** The response will contain the cloud metadata listing (e.g., `ami-id`, `instance-id`, `iam/`) prefixed with `http://169.254.169.254:` on each line. The attacker strips the prefix to recover the original metadata content.**Step 3:** Escalate to IAM credential theft:This returns temporary AWS credentials (`AccessKeyId`, `SecretAccessKey`, `Token`) that can be used to access cloud resources.Impact**Cloud metadata exposure:** Attacker can read instance metadata on AWS (169.254.169.254), GCP (metadata.google.internal), and Azure (169.254.169.254) cloud deployments, including IAM role credentials**Internal network scanning:** Attacker can probe RFC1918 addresses (10.x, 172.16-31.x, 192.168.x) and localhost services to map internal infrastructure**Internal service data exfiltration:** Any HTTP GET-accessible internal service (databases with HTTP interfaces, admin panels, monitoring dashboards) can have its content read and returned to the attacker**No authentication required:** The attack is fully unauthenticated, requiring only network access to the AVideo instanceRecommended RemediationOption 1: Re-validate the redirect target with isSSRFSafeURL() (preferred)Apply the same SSRF check to the redirect URL before fetching it:Option 2: Disable redirect following in get_headers()Prevent `get_headers()` from following redirects entirely by adding `follow_location` to the stream context:Then validate the `Location` header with `isSSRFSafeURL()` before following it manually. This approach prevents the `get_headers()` call itself from performing SSRF via the redirect.**Note:** Option 1 is simpler but still allows `get_headers()` to make an initial request to the redirect target (header-only SSRF). Option 2 eliminates both SSRF vectors. Both options should be combined for defense-in-depth.CreditThis vulnerability was discovered and reported by [bugbunny.ai](https://bugbunny.ai).
CVSS v3.1 score: 8.6