AVideo CVE-2026-43875
MEDIUMSeverity by source
AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N
Primary rating from GitHub Advisory · only source for this CVE.
CVSS VectorGitHub Advisory
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N
Lifecycle Timeline
2DescriptionGitHub Advisory
Summary
plugin/MobileManager/oauth2.php completes an OAuth login by sending an HTTP 302 Location: oauth2Success.php?user=<email>&pass=<HASH> where <HASH> is the victim's stored password hash (md5(hash("whirlpool", sha1(password)))) read directly from the users table. AVideo's own login endpoint (objects/login.json.php) accepts an encodedPass=1 flag that bypasses hashing and performs a direct string comparison between the supplied value and the stored hash. Anyone who captures the redirect URL - via server logs, referrer leakage, or browser history - therefore obtains a credential equivalent to the plaintext password and can fully take over the account, including admin accounts.
Details
Sink: hash inlined in a GET redirect
plugin/MobileManager/oauth2.php:98-102:
$pass = rand();
$users_id = User::createUserIfNotExists($user, $pass, $name, $email, $photoURL);
$adapter->disconnect();
$userObject = new User($users_id);
header("Location: oauth2Success.php?user=" . $userObject->getUser() . "&pass=" . $userObject->getPassword());$userObject->getPassword() returns the raw database column (objects/user.php:159-162):
public function getPassword()
{
return strip_tags($this->password);
}The returned value is the stored password hash for the account (existing or freshly-created). It is transported to the browser as a query-string parameter in the Location: header, so it is written to:
- Web-server access logs (
combined/mainlog formats record the full request line including query string). - Upstream proxy / CDN / WAF logs.
- Any error monitoring / APM that captures request URLs (Sentry, Datadog, New Relic defaults).
- The victim's browser history (persistent local artifact).
- The
Refererheader on subsequent navigation from the renderedoauth2Success.phppage if the page or its assets load any external origin and the browser'sReferrer-Policyis not strict.
Hash equals plaintext for login
objects/login.json.php:182-209:
if (!empty($_GET['user'])) {
$_POST['user'] = $_GET['user'];
}
if (!empty($_GET['pass'])) {
$_POST['pass'] = $_GET['pass'];
}
if (!empty($_GET['encodedPass'])) {
$_POST['encodedPass'] = $_GET['encodedPass'];
}
...
$user = new User(0, $_POST['user'], $_POST['pass']);
...
$resp = $user->login(false, @$_POST['encodedPass']);objects/user.php:1272-1279 passes $encodedPass to find():
if (strtolower($encodedPass) === 'false') {
$encodedPass = false;
}
...
$user = $this->find($this->user, $this->password, true, $encodedPass);objects/user.php:1785-1794:
if ($pass !== false) {
if (!encryptPasswordVerify($pass, $result['password'], $encodedPass)) {
...
return false;
}
}objects/functions.php:2312-2331:
function encryptPasswordVerify(#[\SensitiveParameter] $password, $hash, $encodedPass = false)
{
global $advancedCustom, $global;
if (!$encodedPass || $encodedPass === 'false') {
$passwordSalted = encryptPassword($password);
$passwordUnSalted = encryptPassword($password, true);
} else {
$passwordSalted = $password; // <- direct use, no hashing
$passwordUnSalted = $password;
}
$isValid = $passwordSalted === $hash || $passwordUnSalted === $hash;
...
}When encodedPass is truthy, the supplied value is compared as-is against the stored hash. The captured redirect parameter pass=<HASH> is therefore a valid login credential when replayed with encodedPass=1.
Compounding factors
- The redirect is a raw
Location:(GET), not a POST - the secret is placed in a URL which is by definition non-confidential transport. - No CSRF token, no
stateparameter tied to the session, and no single-use token is used on/plugin/MobileManager/oauth2.php. login.json.phpdoes not require a CSRF token or captcha on the first attempt (checkLoginAttempts()atobjects/user.php:1282only rate-limits after failures, and the attacker succeeds on the first try).- By contrast, the non-plugin flow in
objects/login.json.php:144-145already sets session state server-side ($userObject->login(true)), demonstrating the project already has a safer pattern available.
PoC
Prerequisites: MobileManager plugin enabled and at least one supported login provider (e.g. LoginGoogle) configured with valid keys - both are common production settings for this product.
- Victim initiates the mobile OAuth flow:
GET /plugin/MobileManager/oauth2.php?type=Google- After the victim authorizes at the provider, the server sends:
HTTP/1.1 302 Found
Location: oauth2Success.php?user=victim%40example.com&pass=9d7ab4...stored-hash...This request-line - including the password hash - is written to the web server's access log (default combined format) and to any upstream proxy/CDN log. It also appears in the victim's browser history.
- Attacker obtains
<HASH>from any of those channels. - Attacker logs in as the victim without knowing the plaintext password:
curl -i -c cookies.txt \
'https://target.example.com/objects/login.json.php?user=victim@example.com&pass=<HASH>&encodedPass=1'Expected response: 200 OK with JSON containing id, user, PHPSESSID, isAdmin, email, and a Set-Cookie: PHPSESSID=... that grants full account access. The attacker can now browse, upload, modify the victim's channel, or - if the victim is an admin - access /mvideos and all admin endpoints.
Impact
- Full account takeover of any user who has ever logged in through the MobileManager OAuth endpoint.
- If the victim is an administrator, the attacker gains administrative control of the AVideo instance (user management, plugin config, site-wide content).
- The exposed hash works indefinitely: it remains valid for as long as the victim does not change their password, so a one-time log/history/referrer capture yields a persistent credential.
- Passes silently - from the application's perspective, the attacker is just a legitimate login with
encodedPass=1(a flag the product itself uses for mobile-app "remember me" flows).
Recommended Fix
- Never place the password hash (or any credential-equivalent material) in a URL. In
plugin/MobileManager/oauth2.php, mirror whatobjects/login.json.php:143-146already does for the web flow - establish the session server-side and redirect to a URL with no credentials:
$userObject = new User(0, $user, $pass);
$userObject->login(true); // server-side session
header("Location: oauth2Success.php");- Additionally, remove or hard-restrict the
encodedPassbranch inobjects/functions.php:2319-2329. If a "hash-equivalent" credential must exist for the mobile app, replace it with a short-lived, single-use, server-issued bearer token bound to the session, rather than the persistent database hash. - Add a
stateparameter and CSRF protection on/plugin/MobileManager/oauth2.phpso the redirect cannot be initiated from a third-party origin. - For defense-in-depth, strip query strings containing
pass=from access-log formats and ensureoauth2Success.phpsetsReferrer-Policy: no-referrerwhile it is being deprecated.
AnalysisAI
Password hash exposure in AVideo's MobileManager OAuth redirect enables account takeover when unauthenticated attackers capture the redirect URL from server logs, browser history, or referrer leakage, then replay the hash via the login endpoint's encodedPass bypass. The vulnerability affects all users who authenticate through OAuth (Google, etc.) when the MobileManager plugin is enabled, including administrators, and requires only user interaction to trigger the initial OAuth flow-no active exploitation in the wild has been confirmed at analysis time, but a working proof-of-concept exists and patch has been released by the vendor.
Technical ContextAI
AVideo is a video streaming and management platform written in PHP. The vulnerability chains two distinct design flaws: (1) the MobileManager OAuth callback handler (plugin/MobileManager/oauth2.php) transmits the user's raw database password hash as a query-string parameter in an HTTP 302 redirect (CWE-598: Use of GET Request with Sensitive Query Strings), and (2) the login endpoint (objects/login.json.php) accepts an encodedPass=1 flag that bypasses the normal password hashing pipeline and performs direct string comparison between the supplied value and the stored hash via encryptPasswordVerify() in objects/functions.php. The password hash scheme is md5(hash('whirlpool', sha1(password))), a legacy multi-round scheme. When encodedPass is truthy, the function skips hashing and treats the input as pre-hashed, effectively making the stored database hash a valid login credential if captured. Query-string parameters are automatically logged by web servers (Apache, nginx in combined/main formats), proxies, CDNs, WAFs, and APM tools (Sentry, Datadog, New Relic defaults), plus persisted in browser history and transmitted in Referer headers.
RemediationAI
Apply the vendor-released patch from commit 977cd6930a97571a26da4239e25c8096dd4ecbc1, which eliminates the query-string credential transmission by establishing the session server-side via $userObject->login(true) before the redirect and removing the pass parameter from the Location header. This mirrors the safer pattern already implemented in the web-flow login path. If you cannot immediately patch, disable the MobileManager plugin entirely (impacts mobile app and federated login) or restrict access to /plugin/MobileManager/oauth2.php via network ACL or authentication gateway. Additionally, configure your web server to exclude query strings from access logs (e.g., Apache LogFormat without ? or use mod_logio to log only URI path) and ensure oauth2Success.php sets the HTTP header Referrer-Policy: no-referrer to prevent hash leakage via Referer on subsequent navigation. Review access logs and CDN/WAF/APM logs from the past 90 days for any oauth2Success.php requests with pass= parameters and treat those hashes as compromised-force password resets for affected users. Investigate whether any external domains are loaded by oauth2Success.php that could trigger Referer leakage.
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
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
NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro
The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-5w8w-26ch-v5cw