GHSA-8x77-f38v-4m5j AVideo: Video Moderator Privilege Escalation via Ownership Transfer Enables Arbitrary Video Deletion
SummaryA user with the "Videos Moderator" permission can escalate privileges to perform full video management operations — including ownership transfer and deletion of any video — despite the permission being documented as only allowing video publicity changes (Active, Inactive, Unlisted). The root cause is that `Permissions::canModerateVideos()` is used as an authorization gate for full video editing in `videoAddNew.json.php`, while `videoDelete.json.php` only checks ownership, creating an asymmetric authorization boundary exploitable via a two-step ownership-transfer-then-delete chain.DetailsThe `PERMISSION_INACTIVATEVIDEOS` (ID 11) permission is described as a limited moderator role in `plugin/Permissions/Permissions.php:213`:However, `Permissions::canModerateVideos()` (`Permissions.php:175`) is reused as an authorization gate in multiple locations in `videoAddNew.json.php` that go far beyond status changes:**1. Upload gate bypass** (`videoAddNew.json.php:10`):
`User::canUpload()` (`user.php:2650`) returns `true` if `Permissions::canModerateVideos()` is true, granting moderators upload access.**2. Edit gate bypass** (`videoAddNew.json.php:19`):`Video::canEdit()` correctly checks only `canAdminVideos()` and ownership, but the `|| !Permissions::canModerateVideos()` fallback allows moderators to edit any video.**3. Ownership transfer** (`videoAddNew.json.php:222`):`userCanChangeVideoOwner` defaults to `false` (`CustomizeUser.php:286`), but `canModerateVideos()` provides an unconditional bypass, allowing any moderator to reassign ownership of any video.**4. Delete via ownership** (`videoDelete.json.php:22-28`):`userCanManageVideo()` (`video.php:3614`) checks `canAdminVideos()` (not `canModerateVideos()`), then falls back to ownership. After the ownership transfer in step 3, the moderator is now the owner, so this check passes.The authorization asymmetry: `videoAddNew.json.php` treats `canModerateVideos()` as equivalent to `canAdminVideos()`, but `videoDelete.json.php` and `userCanManageVideo()` do not — creating a gap exploitable by transferring ownership first.Additional fields a moderator can modify beyond their intended scope:`only_for_paid` (line 210) — make premium content free`video_password` (line 211) — change/remove password protection`categories_id` (line 168) — alter content categorization`videoGroups` (line 175) — modify user group visibilityPoC**Prerequisites:** An account with the "Videos Moderator" permission (PERMISSION_INACTIVATEVIDEOS = 11) and a target video ID owned by another user.**Step 1: Transfer ownership of target video to attacker**Expected response: `{"status":true, ...}` — ownership is now transferred to the attacker.**Step 2: Delete the video (now owned by attacker)**Expected response: `{"error":false, ...}` — video is deleted. The owner check at line 22 passes because the moderator is now the recorded owner.**Step 3 (additional impact): Access password-protected video**This removes the video password, granting the moderator (and everyone) access to previously protected content.Impact**Arbitrary video deletion**: A Videos Moderator can delete any video on the platform, including admin-owned content, by first transferring ownership to themselves then deleting.**Content tampering**: Moderator can change paid content flags (`only_for_paid`), video passwords, categories, and user group visibility on any video — all exceeding the documented scope of "change video publicity."**Access control bypass**: Password-protected videos can have their passwords removed, exposing restricted content.**Integrity loss**: Video ownership records are corrupted, making audit trails unreliable.**Availability impact**: Targeted deletion of high-value content with no authorization check appropriate to the destructive action.The blast radius is any video on the platform. Any user granted the "Videos Moderator" role — which administrators may grant freely assuming it only allows status changes — gains effective full video management capabilities.Recommended FixReplace `Permissions::canModerateVideos()` with `Permissions::canAdminVideos()` in `videoAddNew.json.php` where full edit capabilities are granted. Keep `canModerateVideos()` only for the specific status/publicity change operations it was designed for.**Fix for ownership transfer** (`videoAddNew.json.php:222`):**Fix for edit gate** (`videoAddNew.json.php:19`):Then create a separate, narrower code path for moderators that only allows changing video status/publicity fields. Alternatively, refactor `videoAddNew.json.php` to check `canModerateVideos()` only around the specific status-change logic (lines 238-248) and require `canAdminVideos()` for all other fields.
CVSS v3.1 score: 7.6