GHSA-ffr8-fxhv-fv8h: AVideo is Vulnerable to SQL Injection through Subscribe Endpoint via Unsanitized user_id Parameter
SummaryThe `Subscribe::save()` method in `objects/subscribe.php` concatenates the `$this->users_id` property directly into an INSERT SQL query without sanitization or parameterized binding. This property originates from `$_POST['user_id']` in both `subscribe.json.php` and `subscribeNotify.json.php`. An authenticated attacker can inject arbitrary SQL to extract sensitive data from any database table, including password hashes, API keys, and encryption salts.DetailsThe vulnerability exists because of a disconnect between where `intval()` is applied and where the value is used in SQL.**Entry points** — `objects/subscribe.json.php:40` and `objects/subscribeNotify.json.php:23`:**Constructor stores raw value** — `objects/subscribe.php:34`:**`getSubscribeFromID` sanitizes local copies only** — `objects/subscribe.php:137-139`:When `getSubscribeFromID` finds no matching subscription (the attacker simply targets a user_id they haven't subscribed to), `loadFromId()` returns false. The object's `$this->id` remains null, and `$this->users_id` retains the unsanitized injection payload.**Vulnerable sink** — `objects/subscribe.php:88`:**`sqlDAL::writeSql` provides no protection** — `objects/mysql_dal.php:102`:When called without `$formats`/`$values` parameters (as `save()` does), the `eval_mysql_bind()` function at line 636 returns `true` without binding any parameters. The already-concatenated SQL string is passed directly to `$global['mysqli']->prepare()` and `execute()`, executing the injection as the prepared statement itself.PoC**Prerequisites:** An authenticated session on the target AVideo instance.**Step 1: Confirm injection with time-based blind SQLi****Step 2: Extract admin password hash via INSERT subquery**This closes the `VALUES` clause with attacker-controlled data and comments out the rest of the query. The admin password hash is inserted into the `email` column of the `subscribes` table, which can be read back via the subscription list API.**Step 3: Read exfiltrated data**The injected row is readable via any endpoint that queries the `subscribes` table and returns the `email` field (e.g., `getAllSubscribes()`).The same attack works against `objects/subscribeNotify.json.php` via the same `user_id` parameter.Impact**Full database read access:** An attacker with any authenticated account can extract arbitrary data from all database tables using INSERT subqueries, including:User password hashes (`users.pass`)Admin credentialsEncryption salts and API keys from configuration tablesEmail addresses and personal data of all users**Data integrity:** The attacker can insert arbitrary rows into the `subscribes` table.**Two affected endpoints:** Both `subscribe.json.php` and `subscribeNotify.json.php` pass raw `$_POST['user_id']` to the vulnerable code path.Recommended FixApply `intval()` to `$this->users_id` before use in the constructor, or better yet, use parameterized queries in `save()`.**Option 1 — Sanitize in constructor** (minimal fix):**Option 2 — Use parameterized query in save()** (recommended):Option 2 is strongly recommended as it also fixes the unsanitized `$this->email`, `$this->status`, and `getRealIpAddr()` values in both the INSERT and UPDATE paths, preventing any future injection through those fields.
CVSS v3.1: 7.1