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

説明

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:

// 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:

// 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():

// 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:

{
  "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:

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:

cat /tmp/pwned
# uid=33(www-data) gid=33(www-data) groups=33(www-data)

Impact

  • Remote Code Execution: If the LinkedIn API response is compromised, an attacker gains arbitrary command execution as the web server user (www-data).
  • Confidentiality: Full read access to application source code, configuration files (including database credentials), and any data accessible to the web server process.
  • Integrity: Ability to modify application files, inject backdoors, or alter database records.
  • Practical risk is low due to the high attack complexity — exploitation requires compromising a trusted HTTPS API response from LinkedIn. This is primarily a defense-in-depth issue.

Recommended Fix

Sanitize both $uploadUrl and $filePath with escapeshellarg() before interpolation into the shell command. Alternatively, replace the exec() call with PHP's native cURL functions (which are already used elsewhere in the same class):

Option 1 — Minimal fix with escapeshellarg():

// plugin/SocialMediaPublisher/Objects/SocialUploader.php:711-715
static function uploadVideoToLinkedIn($uploadUrl, $filePath)
{
    $shellCmd = 'curl -v -H "Content-Type:application/octet-stream" --upload-file ' .
        escapeshellarg($filePath) . ' ' .
        escapeshellarg($uploadUrl) . ' 2>&1';

Option 2 — Replace shell exec with native PHP cURL (preferred):

static function uploadVideoToLinkedIn($uploadUrl, $filePath)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $uploadUrl);
    curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/octet-stream']);
    curl_setopt($ch, CURLOPT_PUT, true);
    curl_setopt($ch, CURLOPT_INFILE, fopen($filePath, 'r'));
    curl_setopt($ch, CURLOPT_INFILESIZE, filesize($filePath));
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_HEADER, true);
    curl_setopt($ch, CURLOPT_VERBOSE, true);

    $response = curl_exec($ch);
    $headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $headers = substr($response, 0, $headerSize);
    curl_close($ch);

    // Extract ETag from response headers
    $matches = [];
    preg_match('/(etag:)(\s?)(.*)(\n)/i', $headers, $matches);
    $etag = isset($matches[3]) ? trim($matches[3]) : null;

    // ... rest of function
}

Option 2 is strongly preferred as it eliminates the shell execution entirely, removing the injection surface and aligning with the PHP cURL usage already present in initializeLinkedInUploadSession() on line 664.

基本情報

タイプ
reviewed
深刻度
medium
GitHub 上のアドバイザリ
アドバイザリを開く ↗
リポジトリのアドバイザリ
リポジトリのアドバイザリを開く ↗
ソースコード
ソースを見る ↗
公開(アドバイザリ)
2026-03-19 12:45:38 UTC
更新
2026-03-25 18:33:54 UTC
GitHub レビュー済み
2026-03-19 12:45:38 UTC
NVD で公開
2026-03-22

EPSS Score

Score Percentile
0.03% 8.45%

CVSS Scores

Base score Version Severity Vector
5.9 3.1
CVSS:3.1/AV:N/AC:H/PR:H/UI:N/S:U/C:H/I:H/A:N クリックして展開
攻撃ベクター (AV:N)
インターネットなど、ルーティングされたネットワーク越しに遠隔から悪用しうる。端末の前にいる必要はない。
攻撃の複雑さ (AC:H)
到達できても、タイミング・負荷・周辺設定など、揃わないと成功しない局面が多い。
必要な権限 (PR:H)
管理者・SYSTEM など、強い権限を握った状態からでないと実害に結びつきにくい。
ユーザーの関与 (UI:N)
メールのリンクを開く、マクロを有効にするなど、被害者の協力がなくても成立しうる。
スコープ (S:U)
影響は脆弱コンポーネントと同一のセキュリティ権限・信頼境界の内側に収まる。
機密性への影響 (C:H)
広範な機微データの読み取りや持ち出しが現実的。
完全性への影響 (I:H)
権限の奪取や広範なログ改竄など、システムの信頼根拠を揺るがす改ざんが現実的。
可用性への影響 (A:N)
業務継続に支障が出るレベルの停止や劣化は想定されない。

Identifiers

CWEs

CWE id Name
CWE-78 Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection')

Credits

  • offset (reporter)

Affected packages (1)

Vulnerable version ranges and first patched releases as published by GitHub.

Ecosystem Package Vulnerable range First patched Vulnerable functions
composer wwbn/avideo <= 25.0

References

cvelogic Threat Intelligence