Summary
The HLS streaming endpoint (view/hls.php) is vulnerable to a path traversal attack that allows an unauthenticated attacker to stream any private or paid video on the platform. The videoDirectory GET parameter is used in two divergent code paths, one for authorization (which truncates at the first / segment) and one for file access (which preserves .. traversal sequences), creating a split-oracle condition where authorization is checked against one video while content is served from another.
Details
The vulnerability is a split-oracle between the authorization lookup and the filesystem path construction. When hls.php receives a request, it processes $_GET['videoDirectory'] through two independent functions that interpret the input differently.
Step 1, Authorization lookup truncates at first path segment (objects/video.php:1685-1688):
public static function getVideoFromFileName($fileName, $ignoreGroup = false, $ignoreTags = false)
{
// ...
$parts = explode("/", $fileName);
if (!empty($parts[0])) {
$fileName = $parts[0]; // Only takes first segment
}
$fileName = self::getCleanFilenameFromFile($fileName);
// ...
$sql = "SELECT id FROM videos WHERE filename = ? LIMIT 1";
$res = sqlDAL::readSql($sql, "s", [$fileName]);
For input public_video/../private_video, explode("/", ...) yields ["public_video", "..", "private_video"] and only public_video is used for the DB query. The authorization check at hls.php:73 then runs against this public video:
if (isAVideoUserAgent() || ... || User::canWatchVideo($video['id']) || ...) {
Step 2, File path construction preserves the traversal (objects/video.php:4622-4638):
public static function getPathToFile($videoFilename, $createDir = false)
{
$videosDir = self::getStoragePath();
$videoFilename = str_replace($videosDir, '', $videoFilename);
$paths = Video::getPaths($videoFilename, $createDir);
if (preg_match('/index(_offline)?.(m3u8|mp4|mp3)$/', $videoFilename)) {
$paths['path'] = rtrim($paths['path'], DIRECTORY_SEPARATOR);
$paths['path'] = rtrim($paths['path'], '/');
$videoFilename = str_replace($paths['relative'], '', $videoFilename);
$videoFilename = str_replace($paths['filename'], '', $videoFilename);
}
$newPath = addLastSlash($paths['path']) . "{$videoFilename}";
$newPath = str_replace('//', '/', $newPath);
return $newPath;
}
getPaths extracts the clean filename (e.g., public_video) to build the base path /videos/public_video/. Then str_replace($paths['filename'], '', $videoFilename) replaces only the clean name from the full input, leaving the traversal intact: /../private_video/index.m3u8. The concatenation at line 4634 produces /videos/public_video/../private_video/index.m3u8, which the OS resolves to /videos/private_video/index.m3u8.
No mitigations exist in the path:
fixPath()(objects/functionsFile.php:1116) only normalizes slashes, does not filter..- No
realpath()call anywhere in the chain - No
..filtering on thevideoDirectoryparameter - The traversal is in a query parameter, not the URL path, so web server path normalization does not apply
PoC
Prerequisites: An AVideo instance with at least one public video (filename: public_video) and one private/paid video (filename: private_video).
Step 1, Confirm the private video is inaccessible directly:
curl -s "https://target.com/view/hls.php?videoDirectory=private_video" \
| head -5
# Expected: "HLS.php Can not see video [ID] (private_video) cannot watch (ID)"
Step 2, Exploit the split-oracle to stream the private video:
curl -s "https://target.com/view/hls.php?videoDirectory=public_video/../private_video" \
-H "Accept: application/vnd.apple.mpegurl"
# Expected: Valid M3U8 playlist containing private_video's HLS segments
Step 3, Stream the private video content using the returned playlist:
# The M3U8 response contains segment URLs; use ffmpeg or any HLS player:
ffmpeg -i "https://target.com/view/hls.php?videoDirectory=public_video/../private_video" \
-c copy stolen_video.mp4
The authorization check passes because it resolves public_video (the public video), while the file system serves private_video's HLS stream.
Impact
- Any unauthenticated user can stream any private, unlisted, or paid video on the platform by knowing or guessing its filename directory.
- Paid content bypass: Monetized videos protected by pay-per-view or subscription gates can be streamed for free.
- Privacy violation: Videos marked as private or restricted to specific user groups are fully accessible.
- Content theft at scale: Video filenames follow predictable patterns (e.g.,
video_YYYYMMDD_XXXXX), enabling enumeration. An attacker only needs one publicly accessible video to pivot to any other video on the instance. - This affects all AVideo instances with at least one public video, which is the default configuration for any content platform.
Input manipulates file paths to reach files outside the intended directory, such as configuration or credential files. Typical impact: unauthorized file read or write outside the intended directory.
CVE-2026-33292 has a CVSS score of 7.5 (High). The vector is network-reachable, no privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. No fixed version is listed yet, so configuration controls and monitoring matter more in the interim.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Remediation advice
Sanitize the videoDirectory parameter to reject path traversal sequences before any processing occurs. Apply this fix at the top of view/hls.php:
// view/hls.php, after line 16, before line 17
if (empty($_GET['videoDirectory'])) {
forbiddenPage("No directory set");
}
// ADD: Reject path traversal attempts
$_GET['videoDirectory'] = str_replace('\\', '/', $_GET['videoDirectory']);
if (preg_match('/\.\./', $_GET['videoDirectory'])) {
forbiddenPage("Invalid directory");
}
// Normalize: strip leading/trailing slashes, collapse multiples
$_GET['videoDirectory'] = trim($_GET['videoDirectory'], '/');
$_GET['videoDirectory'] = preg_replace('#/+#', '/', $_GET['videoDirectory']);
Additionally, add a realpath() check in getPathToFile as defense-in-depth (objects/video.php:4636):
$newPath = str_replace('//', '/', $newPath);
// ADD: Verify resolved path stays within videos directory
$realPath = realpath($newPath);
$realVideosDir = realpath($videosDir);
if ($realPath === false || strpos($realPath, $realVideosDir) !== 0) {
return false;
}
return $newPath;
Frequently Asked Questions
- What is CVE-2026-33292? CVE-2026-33292 is a high-severity path traversal vulnerability in wwbn/avideo (composer), affecting versions <= 25.0. No fixed version is listed yet. Input manipulates file paths to reach files outside the intended directory, such as configuration or credential files.
- How severe is CVE-2026-33292? CVE-2026-33292 has a CVSS score of 7.5 (High). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of wwbn/avideo are affected by CVE-2026-33292? wwbn/avideo (composer) versions <= 25.0 is affected.
- Is there a fix for CVE-2026-33292? No fixed version is listed for CVE-2026-33292 yet. Monitor the advisory for updates and apply mitigations in the interim.
- Is CVE-2026-33292 exploitable, and should I be worried? Whether CVE-2026-33292 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-33292 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-33292? No fixed version is listed yet. In the interim: Resolve the canonical path after applying any user-supplied input, and verify it remains within the intended directory before accessing it.