GitHub Advisoryadvisory · Packagist

GHSA-vvfw-4m39-fjqf WWBN AVideo has CSRF in configurationUpdate.json.php Enables Full Site Configuration Takeover Including Encoder URL and SMTP Credentials

HIGH Published 2026-04-14 Modified 2026-04-24 Official page ↗
Aliases
CVE-2026-40925
Ecosystem
Packagist
Packages
wwbn/avideo
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L
Weaknesses
CWE-352
Reviewed
2026-04-14

Affected packages

• Packagist wwbn/avideo: <= 29.0 (no fix yet)

Description

Summary `objects/configurationUpdate.json.php` (also routed via `/updateConfig`) persists dozens of global site settings from `$_POST` but protects the endpoint only with `User::isAdmin()`. It does not call `forbidIfIsUntrustedRequest()`, does not verify a `globalToken`, and does not validate the Origin/Referer header. Because AVideo intentionally sets `session.cookie_samesite=None` to support cross-origin iframe embedding, a logged-in administrator who visits an attacker-controlled page will have the browser auto-submit a cross-origin POST that rewrites the site's encoder URL, SMTP credentials, site `` HTML, logo, favicon, contact email, and more in a single request. Details The entire authorization and CSRF check for the endpoint is this block at `objects/configurationUpdate.json.php:10`: ```php require_once $global['systemRootPath'] . 'objects/user.php'; if (!User::isAdmin()) { die('{"error":"' . __("Permission denied") . '"}'); } ``` Immediately after, `$_POST` values are written straight into the global `AVideoConf` object and persisted: ```php // objects/configurationUpdate.json.php $config = new AVideoConf(); $config->setContactEmail($_POST['contactEmail']); // :21 $config->setLanguage($_POST['language']); // :22 $config->setWebSiteTitle($_POST['webSiteTitle']); // :23 $config->setDescription($_POST['description']); // :24 $config->setAuthCanComment($_POST['authCanComment']); // :25 $config->setAuthCanUploadVideos($_POST['authCanUploadVideos']); // :26 // Advanced (default enabled — $global['disableAdvancedConfigurations'] is empty by default): $config->setEncoderURL($_POST['encoder_url']); // :32 $config->setSmtp($_POST['smtp']); // :33 $config->setSmtpAuth($_POST['smtpAuth']); // :34 $config->setSmtpSecure($_POST['smtpSecure']); // :35 $config->setSmtpHost($_POST['smtpHost']); // :36 $config->setSmtpUsername($_POST['smtpUsername']); // :37 $config->setSmtpPassword($_POST['smtpPassword']); // :38 $config->setSmtpPort($_POST['smtpPort']); // :39 $config->setHead($_POST['head']); // :42 // ... // Logo / favicon writes: $fileData = base64DataToImage($_POST['logoImgBase64']); // :68 file_put_contents($global['systemRootPath'] . $photoURL, $fileData); // :71 // favicon base64 → file_put_contents → ImageMagick `convert` invocation (:88-120) echo '{"status":"' . $config->save() . '", ...}'; // :130 ``` Why CSRF actually lands 1. SameSite is intentionally `None`. `objects/include_config.php:144` sets `ini_set('session.cookie_samesite', 'None')` and the adjacent comment states the design: *"SameSite=None is intentional: AVideo supports cross-origin iframe embedding… All state-mutating endpoints that are vulnerable to CSRF must instead enforce a short-lived globalToken (verifyToken)."* This endpoint enforces no such token. 2. Project already ships a CSRF primitive and uses it elsewhere. `objects/functionsSecurity.php:138` defines `forbidIfIsUntrustedRequest()`, and the peer admin endpoint `objects/userUpdate.json.php:18` calls it explicitly. `configurationUpdate.json.php` has no such call — grepping the file confirms no `forbidIfIsUntrustedRequest`, `verifyToken`, `globalToken`, or Origin/Referer check. 3. The request is CORS-simple. The admin UI submits with jQuery `$.ajax(...type: 'post', data: {...})` (see `view/configurations_body.php:753`), which sends `application/x-www-form-urlencoded`. That content type is a CORS "simple" request — no preflight — so any third-party origin can trigger it from a `` with the admin's session cookie attached. 4. Reachable via two paths. Direct `POST /objects/configurationUpdate.json.php` works, and `.htaccess:459` also exposes it at `POST /updateConfig`. Impact primitives unlocked by a single CSRF request • `setEncoderURL()` — redirects future encoder operations (URL metadata fetching, chunked uploads, remote file ingestion in `aVideoEncoder.json.php` / `videoAddNew.json.php`) to the attacker's server. Attacker-controlled encoder responses are trusted downstream for titles, descriptions, download URLs, etc. • `setSmtpHost/Username/Password/Port/Secure/Auth` — the next outbound mail (password reset, signup confirmation, admin notifications) goes through the attacker's SMTP relay, harvesting reset tokens and user credentials. • `setHead()` — attacker-chosen raw HTML is injected into every page's ``, giving persistent site-wide stored XSS (e.g. ``) that fires in every visitor's browser including the admin, enabling session theft of arbitrary users. • `logoImgBase64` / `faviconBase64` — attacker-controlled bytes are `file_put_contents`-ed into the web root under `videos/userPhoto/logo.png` and `videos/favicon.png`. • `setContactEmail`, `setWebSiteTitle`, `setAuthCanUploadVideos`, `setAllow_download`, `setSession_timeout`, `setAdsense`, `setDisable_analytics` — full site policy and branding control. PoC 1. Attacker hosts `evil.html` on any origin: ```html '> document.getElementById('x').submit(); ``` 2. Any user authenticated as AVideo administrator (`User::isAdmin()` true) visits `https://attacker.example.com/evil.html`. Their browser submits the form cross-origin; because `session.cookie_samesite=None`, `PHPSESSID` is included; because it's an `application/x-www-form-urlencoded` POST, no preflight is sent. 3. Server-side check at `configurationUpdate.json.php:10` passes (`User::isAdmin()` is true for the victim), and the body reaches `$config->save()` at `:130`. Response: ```json {"status":"1","respnseLogo":[],"respnseFavicon":null} ``` The site-wide configuration is now rewritten with attacker-chosen values — verifiable by visiting any page and seeing the injected `` in the rendered ``, and by inspecting `videos/configuration.php` / the `configurations` table. 4. Stored-XSS pivot: every subsequent visitor (including other admins) now executes `https://attacker.example.com/evil.js` from the victim site's origin, yielding session theft / full admin takeover on what were previously unrelated accounts. 5. SMTP exfiltration pivot: trigger a password-reset flow on the victim site; the SMTP handshake now goes to `smtp.attacker.com:587` with `attacker:password`, and any future mail from AVideo is observable by the attacker. Impact • Full site configuration takeover from a single cross-origin form…

Related

Alias · CVE (1)

  • CVE-2026-40925 WWBN AVideo is an open source video platform. vulnerability

Weakness · CWE (1)

  • CWE-352 Cross-Site Request Forgery weakness

References