CVE-2026-46337: AVideo Path Traversal Vulnerability

MODERATE
Advisory Identifier: GHSA-w4qq-74h6-58wq
CVSS 5.3
CWE-284 CWE-862 CWE-22
Published
Advisory Summary

CVE-2026-46337 is a MODERATE (CVSS 5.3) path traversal vulnerability (CWE-284: Improper Access Control) affecting AVideo libraries in the Packagist ecosystem. The issue involves unauthenticated arbitrary image read via path traversal in `view/img/image404raw.php`. Remediation is available in the latest vendor maintenance releases.

CVE-2026-46337 at a Glance

CVE Identifier CVE-2026-46337
GHSA Identifier GHSA-w4qq-74h6-58wq
Severity MODERATE
CVSS v3.1 Base Score 5.3
CWE Classification CWE-284: Improper Access Control
Affected Product AVideo
Package Ecosystem Packagist
Published Date
Last Updated

Security Impact

CVSS: 5.3

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:L/I:N/A:N).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality Low (C:L)
Integrity None (I:N)
Availability None (A:N)

How to Fix CVE-2026-46337

To remediate this vulnerability, upgrade all affected 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.

WWBN/AVideo fixed: Latest secure release
Upgrade WWBN/AVideo to Latest secure release
Verify Direct and Transitive Dependencies

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-46337, inspect your project dependencies for AVideo:

inspect dependencies for WWBN/AVideo

Analyze the terminal output to locate any version of 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-284: Improper Access Control, where the product does not restrict or incorrectly restricts access to a resource from an unauthorized actor. In 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

### Summary The endpoint requires **no authentication**. An unauthenticated remote attacker can read arbitrary image files anywhere on disk that the PHP user can open — including private user-profile photos that the application's normal serving wrappers gate behind ACLs, admin-uploaded thumbnails, encrypted-video poster frames, and image content under sibling-app directories reachable via `..` traversal. ### Details `view/img/image404Raw.php` reads the `image` GET parameter and joins it directly into a filesystem path served via `readfile()`. `view/img/image404Raw.php` (full file, current `master` @ `0dbadbcaaa1b415c7db078a72dc4b26d9fac0485`): ```php <?php // Fetch requested image URL $imageURL = !empty($_GET['image']) ? $_GET['image'] : $_SERVER["REQUEST_URI"]; $rootDir = dirname(__FILE__) . '/../../'; if ($imageURL == 'favicon.ico') { $imgLocalFile = "{$rootDir}/videos/{$imageURL}"; } else { $imgLocalFile = "{$rootDir}/{$imageURL}"; // ← attacker-controlled } if (file_exists($imgLocalFile)) { $imageInfo = getimagesize($imgLocalFile); // ← format gate if (empty($imageInfo)) { die('not image'); } // …extension → Content-Type mapping… header("HTTP/1.0 200 OK"); header('Content-Type: ' . $type); header('Content-Length: ' . filesize($imgLocalFile)); readfile($imgLocalFile); // ← exfil bytes exit; } ``` Issues: 1. **No authentication.** The file is reachable via direct GET; no `require` of `globals.php`, no session check, no API-key gate. 2. **No basename / realpath / prefix containment.** `$_GET['image']` is concatenated into `$imgLocalFile` with no `..` filtering, no `realpath()` resolution, no allowlist check against the intended `view/img/` directory. 3. **`getimagesize()` is a magic-bytes check, not a path constraint.** Any file on disk whose first bytes match a recognized image format (`FFD8FF` JPEG, `89504E47` PNG, `474946` GIF, `52494646…57454250` WebP) passes the gate — including images stored outside any ACL'd area of the application. 4. **`$_SERVER["REQUEST_URI"]` fallback** when `image` is empty widens the attack surface (path components in the URI itself land in `$imgLocalFile`). **Re-verified pre-submission** on 2026-05-13 against `view/img/image404Raw.php` blob SHA `c670b0faff4fbea1fd0508f179956975477d4340` — unsafe shape unchanged since first discovery on 2026-05-12. **Recommended fix** — three layered checks, any one alone is insufficient: ```php // view/img/image404Raw.php — proposed fix <?php $imageURL = !empty($_GET['image']) ? $_GET['image'] : ''; if ($imageURL === '') { http_response_code(400); exit('bad request'); } // 1. Reject any path-traversal segment outright. if (strpos($imageURL, '..') !== false || strpos($imageURL, "\0") !== false || strpos($imageURL, '://') !== false) { http_response_code(400); exit('bad request'); } // 2. Resolve to a real path and verify prefix containment under the // intended image directory. $rootDir = realpath(dirname(__FILE__) . '/../../'); $imgLocalFile = realpath($rootDir . '/' . $imageURL); if ($imgLocalFile === false || (strpos($imgLocalFile, $rootDir . '/videos/') !== 0 && strpos($imgLocalFile, $rootDir . '/view/img/') !== 0)) { http_response_code(404); exit('not found'); } // 3. Existing getimagesize() check stays as defense-in-depth. if (!is_file($imgLocalFile)) { http_response_code(404); exit('not found'); } $imageInfo = @getimagesize($imgLocalFile); if (empty($imageInfo)) { http_response_code(404); exit('not image'); } // …rest of the original Content-Type + readfile() flow unchanged… ``` Drop the `$_SERVER["REQUEST_URI"]` fallback entirely; if no `image` parameter is provided, return 400. ### PoC Discovery probe — any HTTP client, no authentication, no cookies: ```http GET /view/img/image404Raw.php?image=../videos/userPhoto/photo1.jpg HTTP/1.1 Host: avideo.example.com ``` If `videos/userPhoto/photo1.jpg` exists on the server, the response is the raw image bytes (HTTP 200, `Content-Type: image/jpeg`). The application's normal user-photo serving wrapper (which can gate by session / channel ownership) is bypassed entirely. Cross-directory probe — read images outside the AVideo install root: ```http GET /view/img/image404Raw.php?image=../../../var/www/other-app/uploads/users/admin.jpg HTTP/1.1 Host: avideo.example.com ``` If the PHP user has read access to a sibling app's image directory, those files are exfiltrable too. Enumeration — iterate over predictable numeric IDs: ``` GET /view/img/image404Raw.php?image=../videos/userPhoto/photo1.jpg GET /view/img/image404Raw.php?image=../videos/userPhoto/photo2.jpg GET /view/img/image404Raw.php?image=../videos/userPhoto/photo3.jpg ... ``` …to harvest all profile images regardless of the application's intended privacy controls. ### Impact **Path traversal → arbitrary image read (CWE-22 + CWE-284).** Affects any AVideo deployment running master through commit `0dbadbca` and likely every release on the supported branches. The attacker: 1. **Bypasses the application's image-content ACLs.** Profile photos under `videos/userPhoto/` and admin-uploaded private thumbnails that AVideo's normal image-serving wrappers gate by session / channel ownership become readable to any anonymous internet user. 2. **Reads images stored outside the AVideo install root.** On shared-hosting / multi-tenant deployments, `..` traversal lets the attacker page into sibling-app upload directories — anywhere the PHP user has read access on disk and the target file's first bytes form a valid image header. 3. **Enables enumeration at scale.** Numeric ID schemes (`photo1.jpg`, `photo2.jpg`, …) and predictable filenames let an attacker harvest every private image on a deployment without detection (each request looks like a single 200-image-OK to the web log). Because the read primitive is restricted to image-magic-bytes files, there is no source-code or credential exfiltration via this primitive alone — but the **privacy / GDPR exposure** is substantial on any deployment that hosts user-uploaded photos. CVSS 5.3 (Medium) reflects the limited but real confidentiality impact; many operators will rate this higher because the leaked content is user-private by intent. This is **not** a silent-fix disclosure — the bug is still present on current `master` at submission time; the maintainer is being notified of a previously-unknown issue.

CVE-2026-46337 Affected AVideo Versions

1 component(s)
Product / Package Ecosystem Affected Versions Fixed Version
WWBN/AVideo
Packagist
≤ 29.0

References

Frequently Asked Questions

What is CVE-2026-46337?
CVE-2026-46337 is a security vulnerability in AVideo involving Unauthenticated Arbitrary Image Read via Path Traversal in `view/img/image404Raw.php` under CWE-284: Improper Access Control.
Which AVideo versions are affected?
Affected versions include releases prior to current release patches across affected packages: WWBN/AVideo.
What version fixes CVE-2026-46337?
Upgrading to current release patches (or the latest patched release for your respective branch) resolves the vulnerability.
Is WWBN/AVideo affected?
Yes, WWBN/AVideo is affected in releases prior to Latest secure release. Upgrade your dependency to Latest secure release or later.
What is the CVSS score of CVE-2026-46337?
CVE-2026-46337 has a CVSS v3.1 base score of 5.3 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N.
What CWE is associated with CVE-2026-46337?
CVE-2026-46337 is classified under CWE-284: Improper Access Control (The product does not restrict or incorrectly restricts access to a resource from an unauthorized actor.).
How can I check Packagist dependencies for CVE-2026-46337?
Run the dependency tree command: 'inspect dependencies for WWBN/AVideo'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-w4qq-74h6-58wq",
  "modified" : "2026-06-09T10:28:43Z",
  "published" : "2026-05-19T16:25:27Z",
  "aliases" : [ "CVE-2026-46337" ],
  "summary" : "AVideo: Unauthenticated Arbitrary Image Read via Path Traversal in `view/img/image404Raw.php`",
  "details" : "### Summary\nThe endpoint requires **no authentication**. An unauthenticated remote attacker can read arbitrary image files anywhere on disk that the PHP user can open — including private user-profile photos that the application's normal serving wrappers gate behind ACLs, admin-uploaded thumbnails, encrypted-video poster frames, and image content under sibling-app directories reachable via `..` traversal.\n\n### Details\n`view/img/image404Raw.php` reads the `image` GET parameter and joins it directly into a filesystem path served via `readfile()`.  `view/img/image404Raw.php` (full file, current `master` @ `0dbadbcaaa1b415c7db078a72dc4b26d9fac0485`):\n\n```php\n<?php\n\n// Fetch requested image URL\n$imageURL = !empty($_GET['image']) ? $_GET['image'] : $_SERVER[\"REQUEST_URI\"];\n$rootDir = dirname(__FILE__) . '/../../';\nif ($imageURL == 'favicon.ico') {\n    $imgLocalFile = \"{$rootDir}/videos/{$imageURL}\";\n} else {\n    $imgLocalFile = \"{$rootDir}/{$imageURL}\";   // ← attacker-controlled\n}\n\nif (file_exists($imgLocalFile)) {\n    $imageInfo = getimagesize($imgLocalFile);   // ← format gate\n    if (empty($imageInfo)) {\n        die('not image');\n    }\n    // …extension → Content-Type mapping…\n    header(\"HTTP/1.0 200 OK\");\n    header('Content-Type: ' . $type);\n    header('Content-Length: ' . filesize($imgLocalFile));\n    readfile($imgLocalFile);   // ← exfil bytes\n    exit;\n}\n```\n\nIssues:\n\n1. **No authentication.** The file is reachable via direct GET; no `require` of `globals.php`, no session check, no API-key gate.\n2. **No basename / realpath / prefix containment.** `$_GET['image']`  is concatenated into `$imgLocalFile` with no `..` filtering, no `realpath()` resolution, no allowlist check against the intended `view/img/` directory.\n3. **`getimagesize()` is a magic-bytes check, not a path constraint.**  Any file on disk whose first bytes match a recognized image format (`FFD8FF` JPEG, `89504E47` PNG, `474946` GIF, `52494646…57454250` WebP) passes the gate — including images stored outside any ACL'd area of the application.\n4. **`$_SERVER[\"REQUEST_URI\"]` fallback** when `image` is empty widens the attack surface (path components in the URI itself land in `$imgLocalFile`).\n\n**Re-verified pre-submission** on 2026-05-13 against `view/img/image404Raw.php` blob SHA `c670b0faff4fbea1fd0508f179956975477d4340` — unsafe shape unchanged since first discovery on 2026-05-12.\n\n**Recommended fix** — three layered checks, any one alone is insufficient:\n\n```php\n// view/img/image404Raw.php — proposed fix\n<?php\n\n$imageURL = !empty($_GET['image']) ? $_GET['image'] : '';\nif ($imageURL === '') {\n    http_response_code(400);\n    exit('bad request');\n}\n\n// 1. Reject any path-traversal segment outright.\nif (strpos($imageURL, '..') !== false\n    || strpos($imageURL, \"\\0\") !== false\n    || strpos($imageURL, '://') !== false) {\n    http_response_code(400);\n    exit('bad request');\n}\n\n// 2. Resolve to a real path and verify prefix containment under the\n//    intended image directory.\n$rootDir = realpath(dirname(__FILE__) . '/../../');\n$imgLocalFile = realpath($rootDir . '/' . $imageURL);\nif ($imgLocalFile === false\n    || (strpos($imgLocalFile, $rootDir . '/videos/') !== 0\n        && strpos($imgLocalFile, $rootDir . '/view/img/') !== 0)) {\n    http_response_code(404);\n    exit('not found');\n}\n\n// 3. Existing getimagesize() check stays as defense-in-depth.\nif (!is_file($imgLocalFile)) {\n    http_response_code(404);\n    exit('not found');\n}\n$imageInfo = @getimagesize($imgLocalFile);\nif (empty($imageInfo)) {\n    http_response_code(404);\n    exit('not image');\n}\n\n// …rest of the original Content-Type + readfile() flow unchanged…\n```\n\nDrop the `$_SERVER[\"REQUEST_URI\"]` fallback entirely; if no `image`\nparameter is provided, return 400.\n\n### PoC\n\nDiscovery probe — any HTTP client, no authentication, no cookies:\n\n```http\nGET /view/img/image404Raw.php?image=../videos/userPhoto/photo1.jpg HTTP/1.1\nHost: avideo.example.com\n```\n\nIf `videos/userPhoto/photo1.jpg` exists on the server, the response is the raw image bytes (HTTP 200, `Content-Type: image/jpeg`). The application's normal user-photo serving wrapper (which can gate by session / channel ownership) is bypassed entirely.\n\nCross-directory probe — read images outside the AVideo install root:\n\n```http\nGET /view/img/image404Raw.php?image=../../../var/www/other-app/uploads/users/admin.jpg HTTP/1.1\nHost: avideo.example.com\n```\n\nIf the PHP user has read access to a sibling app's image directory, those files are exfiltrable too.\n\nEnumeration — iterate over predictable numeric IDs:\n\n```\nGET /view/img/image404Raw.php?image=../videos/userPhoto/photo1.jpg\nGET /view/img/image404Raw.php?image=../videos/userPhoto/photo2.jpg\nGET /view/img/image404Raw.php?image=../videos/userPhoto/photo3.jpg\n...\n```\n\n…to harvest all profile images regardless of the application's intended privacy controls.\n\n### Impact\n\n**Path traversal → arbitrary image read (CWE-22 + CWE-284).** Affects any AVideo deployment running master through commit `0dbadbca` and likely every release on the supported branches. The attacker:\n\n1. **Bypasses the application's image-content ACLs.** Profile photos under `videos/userPhoto/` and admin-uploaded private thumbnails  that AVideo's normal image-serving wrappers gate by session / channel ownership become readable to any anonymous internet user.\n2. **Reads images stored outside the AVideo install root.** On shared-hosting / multi-tenant deployments, `..` traversal lets the  attacker page into sibling-app upload directories — anywhere the PHP user has read access on disk and the target file's first bytes form a valid image header.\n3. **Enables enumeration at scale.** Numeric ID schemes (`photo1.jpg`, `photo2.jpg`, …) and predictable filenames let an attacker harvest every private image on a deployment without detection (each request looks like a single 200-image-OK to the web log).\n\nBecause the read primitive is restricted to image-magic-bytes files, there is no source-code or credential exfiltration via this primitive alone — but the **privacy / GDPR exposure** is substantial on any deployment that hosts user-uploaded photos. CVSS 5.3 (Medium) reflects the limited but real confidentiality impact; many operators will rate this higher because the leaked content is user-private by intent.\n\nThis is **not** a silent-fix disclosure — the bug is still present on current `master` at submission time; the maintainer is being\nnotified of a previously-unknown issue.",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N"
  }, {
    "type" : "CVSS_V4",
    "score" : "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:L/VI:N/VA:N/SC:N/SI:N/SA:N"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Packagist",
      "name" : "WWBN/AVideo"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0"
      }, {
        "last_affected" : "29.0"
      } ]
    } ]
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/WWBN/AVideo/security/advisories/GHSA-w4qq-74h6-58wq"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-46337"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/WWBN/AVideo"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-22", "CWE-284", "CWE-862" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-19T16:25:27Z",
    "nvd_published_at" : "2026-05-29T14:16:31Z"
  }
}