Skip to main content

AVideo CVE-2026-45610

| EUVDEUVD-2026-33309 MEDIUM
Missing Authentication for Critical Function (CWE-306)
2026-05-15 https://github.com/WWBN/AVideo GHSA-3mv2-vmwh-rwfx
5.7
CVSS 3.1 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
5.7 MEDIUM
AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:H/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
Required
Scope
Unchanged
Confidentiality
None
Integrity
High
Availability
None

Lifecycle Timeline

2
Source Code Evidence Fetched
May 15, 2026 - 19:35 vuln.today
Analysis Generated
May 15, 2026 - 19:35 vuln.today

DescriptionGitHub Advisory

Summary

Type: Cross-site request forgery on the 2FA toggle. plugin/LoginControl/set.json.php accepts POST type=set2FA value=false, calls LoginControl::setUser2FA(User::getId(), false) on the session-authenticated user, and returns. There is no forbidIfIsUntrustedRequest() call, no isTokenValid() check, no X-CSRF-Token/SameSite enforcement, and no re-authentication step. A cross-origin page that the victim visits while logged into the AVideo dashboard issues the POST via a hidden form (or fetch without credentials:"omit") and disables the victim's 2FA in one request. The next phishing/credential-stuffing attempt against that account no longer needs the second factor. File: plugin/LoginControl/set.json.php, lines 1-37. Root cause: the developer relied on the User::isLogged() check at line 9 as the only auth, then dispatched directly into LoginControl::setUser2FA(User::getId(), $value=='true'). Other AVideo state-changing endpoints in the same codebase (videoUpdateUsage.json.php, videoStatus.json.php, videoRotate.json.php, etc.) call forbidIfIsUntrustedRequest('<name>') to compare Origin/Referer against the AVideo domain; this endpoint simply omits the call. The session cookie carries the user's identity on every cross-origin POST, so any attacker page can speak for the logged-in user on this endpoint.

Affected Code

File: plugin/LoginControl/set.json.php, lines 1-37.

php
<?php
require_once '../../videos/configuration.php';
_session_write_close();
header('Content-Type: application/json');

$obj = new stdClass();
$obj->error = true;
$obj->msg = "";
if (!User::isLogged()) {
    $obj->msg = "Not logged";
    die(json_encode($obj));
}
if (empty($_POST['type'])) {
    $obj->msg = "Type is empty";
    die(json_encode($obj));
}
if (!isset($_POST['value'])) {
    $obj->msg = "value is empty";
    die(json_encode($obj));
}

$cu = AVideoPlugin::loadPluginIfEnabled('LoginControl');

if (empty($cu)) {
    $obj->msg = "Plugin not enabled";
    die(json_encode($obj));
}

$obj->error = false;
switch ($_POST['type']) {
    case 'set2FA':
        LoginControl::setUser2FA(User::getId(), $_POST['value']=="true" ? true : false);  // <-- BUG: no CSRF gate, no re-auth
        break;
}

die(json_encode($obj));

Why it's wrong: disabling a victim's second factor is exactly the kind of state change the AVideo CSRF helper forbidIfIsUntrustedRequest() exists to protect. Compare with objects/comments_like.json.php:18 (forbidIfIsUntrustedRequest('comments_like')) - comments-likes get CSRF protection, but the 2FA toggle does not. Beyond CSRF, security-sensitive toggles like 2FA-disable conventionally also require either the current 2FA code or a password re-prompt: a malicious browser extension, an XSS that lands in any AVideo subdomain, or a compromised tab can otherwise flip the bit silently. None of those mitigations exist here.

Exploit Chain

  1. Attacker hosts https://attacker.example/avideo-2fa-off.html containing:
html
   <form id="f" action="https://avideo.example/plugin/LoginControl/set.json.php" method="POST">
     <input type="hidden" name="type"  value="set2FA">
     <input type="hidden" name="value" value="false">
   </form>
   <script>document.getElementById('f').submit();</script>

State: page is live and indexable.

  1. Attacker delivers the page to a victim who is logged in to avideo.example (open redirect on a trusted partner, ad campaign, IM phishing link, encyclopedic-looking forum post). The victim's browser opens the page; the form auto-submits to AVideo. State: cross-origin POST hits set.json.php with the victim's session cookie attached (the cookie's SameSite attribute is set to Lax/None by AVideo's defaults so the cross-origin POST succeeds for top-level navigations).
  2. set.json.php:9 confirms User::isLogged() (true, victim's session is valid). Lines 13-19 see type=set2FA, value=false. Line 30-32 calls LoginControl::setUser2FA(victim_user_id, false) and persists the change. State: victim's 2FA is now disabled in users.externalOptions.LoginControl.is2FAEnabled.
  3. Victim sees a generic "operation completed" JSON response in a redirected browser tab (or no visible feedback at all if the form lands in an iframe). State: victim notices nothing unusual.
  4. Attacker (in a separate session) attempts credential stuffing or password-spray against avideo.example/objects/login.json.php. Without the second factor, any one of: a previously leaked password, a successful credential-stuffing match, or a spear-phishing-collected password completes the login. State: attacker holds full session for victim's account.
  5. Final state: the second factor that the victim explicitly enabled was silently disabled across the wire by visiting an attacker-hosted page. The whole chain takes one HTTP POST and zero clicks beyond the initial visit.

Security Impact

Severity: sec-moderate. CVSS 6.5: network attack, low complexity, low privileges (the attacker themselves are unauthenticated; the victim must be a logged-in AVideo user; this is captured by PR:L because the action's effect requires the victim's session), user interaction required (visit attacker page), scope unchanged, no confidentiality directly, high integrity (the victim's 2FA configuration is silently corrupted), no availability claim. Attacker capability: with one cross-origin POST, the attacker turns a victim's 2FA-protected account into a plain password-only account. Combined with any password leak, credential-stuffing match, or successful phishing of the password, the account is fully compromised. The change is permanent until the victim notices and re-enables 2FA, and AVideo does not raise an audit-log event when 2FA is disabled (see LoginControl::setUser2FA - it simply writes the boolean), so detection is unlikely. Preconditions: AVideo deployment with the LoginControl plugin enabled (the plugin shipping the 2FA feature); the victim is logged in to AVideo at the moment they visit the attacker page; the AVideo session cookie does not have SameSite=Strict (the deployment default is SameSite=Lax per objects/phpsessionid.json.php:53, which still allows cross-origin top-level POSTs from a form auto-submit). Differential: source-inspection-verified. set.json.php does not contain forbidIfIsUntrustedRequest, isTokenValid, verifyToken, or any equivalent string; the entire body of the file is reproduced above. With the suggested fix below, the same cross-origin POST returns a 403 with Invalid Request and the setUser2FA call never fires.

Suggested Fix

Add the same CSRF gate every other state-changing endpoint in this codebase uses, and require the current 2FA code (or a password re-prompt) when the user is *disabling* the second factor.

diff
--- a/plugin/LoginControl/set.json.php
+++ b/plugin/LoginControl/set.json.php
@@ -9,6 +9,8 @@
 if (!User::isLogged()) {
     $obj->msg = "Not logged";
     die(json_encode($obj));
 }
+forbidIfIsUntrustedRequest('LoginControl-set');
+
 if (empty($_POST['type'])) {
     $obj->msg = "Type is empty";
     die(json_encode($obj));
@@ -28,7 +30,15 @@
 $obj->error = false;
 switch ($_POST['type']) {
     case 'set2FA':
-        LoginControl::setUser2FA(User::getId(), $_POST['value']=="true" ? true : false);
+        $newValue = ($_POST['value'] == 'true');
+        // Require the current 2FA code (or a password re-prompt) when DISABLING 2FA;
+        // turning it on is fine, turning it off needs a step-up.
+        if (!$newValue && !LoginControl::confirmStepUpForCurrentUser($_POST['confirm'] ?? '')) {
+            $obj->error = true;
+            $obj->msg = __('Re-authentication required to disable 2FA');
+            die(json_encode($obj));
+        }
+        LoginControl::setUser2FA(User::getId(), $newValue);
         break;
 }

Defence-in-depth: the AVideo session cookie should be issued with SameSite=Strict for the management dashboard's first-party POSTs; the public read-only player can keep a separate SameSite=Lax cookie. Audit-log every 2FA-disable event with the source IP and user agent so an unexpected disable is visible to the operator.

AnalysisAI

Cross-site request forgery in AVideo's LoginControl plugin allows remote attackers to disable two-factor authentication for authenticated victims through a single malicious HTTP request. The vulnerability exists in plugin/LoginControl/set.json.php which accepts POST requests to toggle 2FA without CSRF token validation, origin verification, or re-authentication. Attackers deliver a weaponized webpage containing a hidden form that auto-submits to the vulnerable endpoint; when a logged-in AVideo administrator visits this page, their 2FA protection is silently stripped, enabling subsequent credential-based account takeover. The flaw is confirmed through GitHub security advisory GHSA-3mv2-vmwh-rwfx with source code evidence showing the endpoint performs only session authentication (User::isLogged()) while omitting the forbidIfIsUntrustedRequest() protection used throughout the rest of the codebase. No public exploit code identified at time of analysis, though the attack is trivial to weaponize given the detailed advisory.

Technical ContextAI

AVideo is a PHP-based video streaming platform (composer package wwbn/avideo). The vulnerability stems from CWE-306 (Missing Authentication for Critical Function) in the LoginControl plugin's JSON API endpoint. Modern web applications protect state-changing operations through CSRF defenses: anti-CSRF tokens embedded in forms, SameSite cookie attributes (Strict/Lax), or origin/referer header validation. AVideo implements a centralized CSRF guard function forbidIfIsUntrustedRequest() used across endpoints like videoUpdateUsage.json.php and videoStatus.json.php, which compares the HTTP Origin/Referer header against the application's trusted domain. The 2FA toggle endpoint bypasses this architecture entirely-it validates only that User::isLogged() returns true (session cookie present) before invoking LoginControl::setUser2FA() to persist the boolean change. Since browsers attach session cookies to cross-origin POST requests when SameSite is Lax (AVideo's default per phpsessionid.json.php:53) or absent, any attacker-controlled page can forge authenticated requests. The absence of step-up authentication (requiring current 2FA code or password when disabling 2FA) further violates security best practices for high-value account settings.

RemediationAI

No vendor-released patch identified at time of analysis. The GitHub advisory at https://github.com/WWBN/AVideo/security/advisories/GHSA-3mv2-vmwh-rwfx provides a detailed code-level fix that administrators with PHP modification capability can apply manually: insert forbidIfIsUntrustedRequest('LoginControl-set') immediately after the User::isLogged() check in plugin/LoginControl/set.json.php (line 11), which enforces origin header validation against the trusted AVideo domain and returns HTTP 403 for cross-origin requests. Additionally, implement step-up authentication by requiring the current 2FA code or password confirmation when the user attempts to disable (not enable) 2FA, preventing both CSRF and malicious browser extension attacks. For organizations unable to modify source code, apply these compensating controls with noted trade-offs: (1) Configure the AVideo session cookie with SameSite=Strict attribute in objects/phpsessionid.json.php line 53, which blocks all cross-origin cookie attachment including legitimate same-site subdomain requests-test thoroughly against video embed workflows. (2) Deploy a Web Application Firewall rule blocking POST requests to /plugin/LoginControl/set.json.php where the Origin or Referer header does not match the AVideo domain, though this may break mobile apps or legitimate API clients that omit these headers. (3) Implement network-level IP allowlisting for the /plugin/LoginControl/ path restricting access to internal management networks only, which eliminates the attack surface entirely but requires dedicated admin access infrastructure. Monitor AVideo's GitHub repository and security advisories for official patch release; subscribe to notifications at https://github.com/WWBN/AVideo/security/advisories for updates.

CVE-2017-1000117 HIGH POC
8.8 Oct 05

A malicious third-party can give a crafted "ssh://..." URL to an unsuspecting victim, and an attempt to visit the URL ca

CVE-2024-52875 HIGH POC
8.8 Jan 31

GFI Kerio Control versions 9.2.5 through 9.4.5 contain an HTTP response splitting vulnerability in the dest parameter of

CVE-2016-5385 HIGH POC
8.1 Jul 19

PHP through 7.0.8 does not attempt to address RFC 3875 section 4.1.18 namespace conflicts and therefore does not protect

CVE-2013-2248 MEDIUM POC
5.8 Jul 20

Multiple open redirect vulnerabilities in Apache Struts 2.0.0 through 2.3.15 allow remote attackers to redirect users to

CVE-2012-6499 MEDIUM POC
5.8 Jan 12

Open redirect vulnerability in age-verification.php in the Age Verification plugin 0.4 and earlier for WordPress allows

CVE-2015-2863 MEDIUM POC
4.3 Jul 20

Open redirect vulnerability in Kaseya Virtual System Administrator (VSA) 7.x before 7.0.0.29, 8.x before 8.0.0.18, 9.0 b

CVE-2017-3528 MEDIUM POC
5.4 Apr 24

Vulnerability in the Oracle Applications Framework component of Oracle E-Business Suite (subcomponent: Popup windows (li

CVE-2012-0518 MEDIUM
4.7 Oct 16

Unspecified vulnerability in the Oracle Application Server Single Sign-On component in Oracle Fusion Middleware 10.1.4.3

CVE-2024-21641 MEDIUM POC
6.5 Jan 05

Flarum is open source discussion platform software. Rated medium severity (CVSS 6.5), this vulnerability is remotely exp

CVE-2015-5354 MEDIUM POC
5.8 Jul 01

Open redirect vulnerability in Novius OS 5.0.1 (Elche) allows remote attackers to redirect users to arbitrary web sites

CVE-2015-5461 MEDIUM POC
6.4 Jul 08

Open redirect vulnerability in the Redirect function in stageshow_redirect.php in the StageShow plugin before 5.0.9 for

CVE-2024-22891 CRITICAL POC
9.8 Mar 01

Nteract v.0.28.0 was discovered to contain a remote code execution (RCE) vulnerability via the Markdown link. Rated crit

Share

CVE-2026-45610 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy