GIVE YOUR AGENT THE EVIDENCE

Set up in your agent.

One prompt to get started. Paste it into your coding agent to connect cve.new through MCP and bring vulnerability context into your workflow.

Your agent needs remote MCP support and access to https://cve.new/mcp.

Read the setup guide

GIVE YOUR AGENT THE EVIDENCE

Investigate in your agent.

Turn this advisory into a focused investigation. Ask your agent to check your project’s versions, explain the evidence, and suggest a compatible fix.

Your agent needs remote MCP support and access to https://cve.new/mcp.

Read the setup guide

GHSA-wfq5-qgqp-hvhvmedium5.3

Unauthenticated Reflected XSS via innerHTML in AVideo

Check your stack

The advisory, in context

Summary

AVideo contains a reflected XSS vulnerability that allows unauthenticated attackers to execute arbitrary JavaScript in a victim's browser. User input from a URL parameter flows through PHP's json_encode() into a JavaScript function that renders it via innerHTML, bypassing encoding and achieving full script execution.

Root Cause

The vulnerability is caused by two issues working together:

1. Source: Unescaped user input passed to JavaScript (videoNotFound.php)

File: view/videoNotFound.php line 49

if (!empty($_REQUEST['404ErrorMsg'])) {
    echo 'avideoAlertInfo(' . json_encode($_REQUEST['404ErrorMsg']) . ');';
}

PHP's json_encode() with default flags only escapes quotes (" → \") and backslashes. It does NOT escape HTML special characters (<, >, /). The resulting string contains raw HTML tags that are passed directly to JavaScript.

2. Sink: innerHTML renders HTML tags as executable DOM (script.js)

File: view/js/script.js

function avideoAlertInfo(msg) {            // line ~1891
    avideoAlert("", msg, 'info');           // calls ↓
}

function avideoAlert(title, msg, type) {   // line ~1270
    avideoAlertHTMLText(title, msg, type);  // calls ↓
}

function avideoAlertHTMLText(title, msg, type) {  // line ~1451
    var span = document.createElement("span");
    span.innerHTML = msg;                  // line 1464 — XSS SINK
    swal({ content: span });
}

innerHTML parses the string as HTML. Any <img>, <svg>, or other HTML tags with event handlers are instantiated as real DOM elements, triggering JavaScript execution.

Data Flow

URL parameter (?404ErrorMsg=PAYLOAD)
    → $_REQUEST['404ErrorMsg']
    → json_encode()          ← does NOT escape < > /
    → avideoAlertInfo()
    → avideoAlert()
    → avideoAlertHTMLText()
    → span.innerHTML = msg   ← renders HTML tags, executes JS

Proof of Concept

https://localhost/view/videoNotFound.php?404ErrorMsg=<img src=x onerror=alert(document.domain)>

<img width="1918" height="1035" alt="image" src="https://github.com/user-attachments/assets/20077ce2-5b49-4bd3-a7df-ab48be786cc1" />

The page renders:

avideoAlertInfo("<img src=x onerror=alert(document.domain)>");

Which flows to span.innerHTML = "<img src=x onerror=alert(document.domain)>". The browser creates an <img> element, src=x fails to load, onerror fires alert(document.domain).

Affected Code

File Line Issue
view/videoNotFound.php 49 json_encode() does not escape < > for HTML context
view/js/script.js 1464 span.innerHTML = msg renders user input as HTML
view/js/script.js 1282 span.innerHTML = msg in avideoAlertWithCookie()
view/js/script.js 1335 span.innerHTML = __(msg,true) in avideoConfirm()
view/js/script.js 1358 span.innerHTML = msg in avideoAlertOnceForceConfirm()

The innerHTML sink exists in 4 functions. Any future code that passes user input to avideoAlertInfo(), avideoAlertWarning(), avideoAlertDanger(), or avideoAlertSuccess() will create additional XSS vectors.

Remediation

Fix 1: Escape HTML in PHP (source fix)

// view/videoNotFound.php line 49
// BEFORE (vulnerable):
echo 'avideoAlertInfo(' . json_encode($_REQUEST['404ErrorMsg']) . ');';

// AFTER (fixed):
echo 'avideoAlertInfo(' . json_encode($_REQUEST['404ErrorMsg'], JSON_HEX_TAG | JSON_HEX_AMP) . ');';

JSON_HEX_TAG converts < → \u003C and > → \u003E, preventing HTML injection.

Fix 2: Use textContent instead of innerHTML (sink fix, recommended)

// view/js/script.js - all alert functions
// BEFORE (vulnerable):
span.innerHTML = msg;

// AFTER (fixed):
span.textContent = msg;

textContent treats the string as plain text — HTML tags are displayed literally, never parsed or executed.

Fix 3: Add Content-Security-Policy header (defense in depth)

Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'

Impact

  • Session hijacking — steal PHPSESSID cookie (not HttpOnly by default)
  • Account takeover — use stolen session to change password or email
  • Phishing — inject a realistic login form inside the SweetAlert modal
  • Worm propagation — inject self-spreading payloads via comments/messages
  • Admin compromise — send crafted link to admin, steal session, gain full control

Affected packages

Start with the recorded fix for your release branch. Check your installed version and test compatibility before upgrading. Fixing this advisory does not rule out other vulnerabilities in the release.

wwbn/avideo Packagist
Ecosystem versions

Earlier releases through 25.0 (inclusive)

No fix recorded for this interval.

16 explicitly affected versions

10.4, 10.8, 11, 11.1, 11.1.1, 11.5, 11.6, 12.4, 14.3, 14.3.1, 14.4, 18.0, 21.0, 22.0, 24.0, 25.0

View affected-version evidence
{
  "ranges": [
    {
      "events": [
        {
          "introduced": "0"
        },
        {
          "last_affected": "25.0"
        }
      ],
      "type": "ECOSYSTEM"
    }
  ],
  "versions": [
    "10.4",
    "10.8",
    "11",
    "11.1",
    "11.1.1",
    "11.5",
    "11.6",
    "12.4",
    "14.3",
    "14.3.1",
    "14.4",
    "18.0",
    "21.0",
    "22.0",
    "24.0",
    "25.0"
  ]
}

References