Średnia

AVideo: Password Hash Leak in MobileManager OAuth Redirect URL Enables Account Takeover

  • Ujawniono: 05.05.2026
  • Aktualizacja: 11.10.2026 10:22

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:

php
$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):

php
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 / main log 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 Referer header on subsequent navigation from the rendered oauth2Success.php page if the page or its assets load any external origin and the browser's Referrer-Policy is not strict.

Hash equals plaintext for login

objects/login.json.php:182-209:

php
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():

php
if (strtolower($encodedPass) === 'false') {
    $encodedPass = false;
}
...
$user = $this->find($this->user, $this->password, true, $encodedPass);

objects/user.php:1785-1794:

php
if ($pass !== false) {
    if (!encryptPasswordVerify($pass, $result['password'], $encodedPass)) {
        ...
        return false;
    }
}

objects/functions.php:2312-2331:

php
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 state parameter tied to the session, and no single-use token is used on /plugin/MobileManager/oauth2.php.
  • login.json.php does not require a CSRF token or captcha on the first attempt (checkLoginAttempts() at objects/user.php:1282 only rate-limits after failures, and the attacker succeeds on the first try).
  • By contrast, the non-plugin flow in objects/login.json.php:144-145 already 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.

  1. Victim initiates the mobile OAuth flow:

    GET /plugin/MobileManager/oauth2.php?type=Google
  2. 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.

  3. Attacker obtains <HASH> from any of those channels.

  4. Attacker logs in as the victim without knowing the plaintext password:

    bash
    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

  1. Never place the password hash (or any credential-equivalent material) in a URL. In plugin/MobileManager/oauth2.php, mirror what objects/login.json.php:143-146 already does for the web flow — establish the session server-side and redirect to a URL with no credentials:

    php
    $userObject = new User(0, $user, $pass);
    $userObject->login(true);   // server-side session
    header("Location: oauth2Success.php");
  2. Additionally, remove or hard-restrict the encodedPass branch in objects/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.

  3. Add a state parameter and CSRF protection on /plugin/MobileManager/oauth2.php so the redirect cannot be initiated from a third-party origin.

  4. For defense-in-depth, strip query strings containing pass= from access-log formats and ensure oauth2Success.php sets Referrer-Policy: no-referrer while it is being deprecated.

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka Composer wwbn/avideo <= 29.0 brak poprawki

Odnośniki

Ocena CVSS 6.8/10
Wektor CVSS
CVSS:3.1/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:N
Słabość (CWE)
CWE-598
Platforma
Composer
Paczka
wwbn/avideo
Ujawniono
05.05.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-5w8w-26ch-v5cw - CC BY 4.0

Historia podatności: wwbn/avideo

Wszystkie opisane podatności tej paczki (Paczka Composer), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (160) w archiwum
Wszystkich wpisów
160
Pierwsza → ostatnia
04.2022 06.2026
Bez poprawki
143
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 14
  • Wysoka 61
  • Średnia 83
  • Niska 2

Ujawnienia w latach

  1. 2022: 2
  2. 2023: 5
  3. 2024: 5
  4. 2025: 0
  5. 2026: 148
Istotność:
  1. Wysoka · 8.8 CVE-2026-45578 <= 29.0 brak poprawki
  2. AVideo: Password Hash Leak in MobileManager OAuth Redirect URL Enables Account Takeover ten wpis
    Średnia · 6.8 CVE-2026-43875 <= 29.0 brak poprawki
  3. Wysoka · 9.8 CVE-2026-41304 <= 29.0 brak poprawki
  4. Wysoka · 9.3 CVE-2026-41064 <= 29.0 brak poprawki
Pokaż więcej (20) Widać 20 z 76

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.