CVE-2026-41062 is a medium-severity (CVSS 6.5) Path Traversal vulnerability in wwbn/avideo. No vendor fix is recorded yet; mitigation options are listed below.
WWBN/AVideo has an incomplete fix for a directory traversal bypass via query string in ReceiveImage downloadURL parameters
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
Exploitation and automatability from CISA’s SSVC triage for CVE-2026-41062.
EPSS Exploitation Probability
EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.
How urgent is this, really
CVE-2026-41062 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.
Where this sits among everything scored
Of 378,567 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.
Real-World Exposure
wwbn/avideoReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.
Description
Summary
The directory traversal fix introduced in commit 2375eb5e0 for objects/aVideoEncoderReceiveImage.json.php only checks the URL path component (via parse_url($url, PHP_URL_PATH)) for .. sequences. However, the downstream function try_get_contents_from_local() in objects/functionsFile.php uses explode('/videos/', $url) on the full URL string including the query string. An attacker can place the /videos/../../ traversal payload in the query string to bypass the security check and read arbitrary files from the server filesystem.
Details
The security fix at commit 2375eb5e0 added a traversal check at objects/aVideoEncoderReceiveImage.json.php:49:
$decodedPath = urldecode((string)(parse_url($_REQUEST[$value], PHP_URL_PATH) ?? ''));
if (strpos($decodedPath, '..') !== false) {
unset($_REQUEST[$value]);
}
This only inspects the path component of the URL. For a URL like http://TARGET/x?a=/videos/../../etc/passwd, parse_url() returns /x as the path — no .. is found.
The URL then passes through isValidURL() (objects/functions.php:4203) which accepts it because FILTER_VALIDATE_URL considers .. in query strings valid per RFC 3986.
It also passes isSSRFSafeURL() (objects/functions.php:4264) because the host matches webSiteRootURL, causing an early return at line 4294.
The URL reaches url_get_contents() (objects/functions.php:1938) which calls try_get_contents_from_local() (objects/functionsFile.php:214):
function try_get_contents_from_local($url)
{
// ...
$parts = explode('/videos/', $url);
if (!empty($parts[1])) {
// ...
$tryFile = "{$global['systemRootPath']}{$encoder}videos/{$parts[1]}";
if (file_exists($tryFile)) {
return file_get_contents($tryFile);
}
}
return false;
}
explode('/videos/', $url) operates on the entire URL string including the query string. For the malicious URL, $parts[1] becomes ../../../../../../etc/passwd, constructing a path like /var/www/html/AVideo/Encoder/videos/../../../../../../etc/passwd which PHP's filesystem functions resolve to /etc/passwd.
The file content is returned to the caller and written to the video's thumbnail path via _file_put_contents(). All four downloadURL_* parameters (downloadURL_image, downloadURL_gifimage, downloadURL_webpimage, downloadURL_spectrumimage) are affected.
PoC
Prerequisites: An authenticated AVideo user account with upload permission and an existing video they own (with known videos_id).
-
Identify the AVideo instance's domain (e.g.,
https://avideo.example.com). -
Send a POST request to the ReceiveImage endpoint with the traversal payload in the query string:
curl -s -b "PHPSESSID=<session_cookie>" \
"https://avideo.example.com/objects/aVideoEncoderReceiveImage.json.php" \
-d "videos_id=<YOUR_VIDEO_ID>" \
-d "downloadURL_image=http://avideo.example.com/x?a=/videos/../../../../../../etc/passwd"
-
The response will include
jpgDestSizeindicating the file was read and written (confirming file existence and revealing file size). -
For files that pass image validation (e.g., other users' uploaded images at known paths), the content persists at the video's thumbnail URL and can be retrieved:
curl -s "https://avideo.example.com/videos/<videoFileName>.jpg"
- Non-image files (e.g.,
/etc/passwd, configuration files) are written but then deleted bydeleteInvalidImage(). However, file existence and size are still leaked, and a race condition exists between the write and the deletion.
Impact
- Arbitrary file read: An authenticated user with upload permission can read any file on the server filesystem that the web server process has access to. Files that pass image validation (PNG/JPEG/GIF) are fully exfiltrable via the video thumbnail URL.
- Information disclosure: For non-image files, file existence and size are leaked through the
jpgDestSizeresponse field. - Configuration exposure: Server configuration files, database credentials (
videos/configuration.php), and other sensitive data can be targeted. While PHP files would be deleted bydeleteInvalidImage, there is a race window between write and deletion. - Bypass of security fix: This directly bypasses the path traversal mitigation added in commit 2375eb5e0.
Recommended Fix
The .. check in aVideoEncoderReceiveImage.json.php should inspect the full URL (after URL-decoding), not just the path component. Additionally, try_get_contents_from_local() should validate its derived path.
Fix 1 — Check the full URL in ReceiveImage (objects/aVideoEncoderReceiveImage.json.php:49):
// Replace:
$decodedPath = urldecode((string)(parse_url($_REQUEST[$value], PHP_URL_PATH) ?? ''));
if (strpos($decodedPath, '..') !== false) {
// With:
$decodedFull = urldecode((string)$_REQUEST[$value]);
if (strpos($decodedFull, '..') !== false) {
Fix 2 — Add path validation in try_get_contents_from_local (objects/functionsFile.php:229):
$tryFile = "{$global['systemRootPath']}{$encoder}videos/{$parts[1]}";
// Add traversal check:
$realTryFile = realpath($tryFile);
$videosDir = realpath("{$global['systemRootPath']}{$encoder}videos/");
if ($realTryFile === false || !str_starts_with($realTryFile, $videosDir)) {
return false;
}
if (file_exists($tryFile)) {
return file_get_contents($tryFile);
}
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐘Packagist | wwbn/avideo | all versions | No fix |
Detection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for wwbn/avideo, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Remediation status
No patched version of wwbn/avideo has shipped for CVE-2026-41062 yet. Where your build allows, override or pin the dependency away from the vulnerable range, and apply any maintainer-recommended mitigation.
Mitigate without a patch
If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.
How O3 protects you
O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-41062 can be triaged on real exposure rather than presence alone.
Tailored to CVE-2026-41062. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.
Frequently Asked Questions
Is CVE-2026-41062 in your dependencies?
O3 Security finds CVE-2026-41062 across Packagist dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.