Skip to main content

AVideo CVE-2026-43877

MEDIUM
Cross-Site Request Forgery (CSRF) (CWE-352)
2026-05-05 https://github.com/WWBN/AVideo GHSA-jw8g-5j46-44rp
5.4
CVSS 3.1 · GitHub Advisory
Share

Severity by source

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

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

CVSS VectorGitHub Advisory

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

Lifecycle Timeline

2
Source Code Evidence Fetched
May 05, 2026 - 20:01 vuln.today
Analysis Generated
May 05, 2026 - 20:01 vuln.today

DescriptionGitHub Advisory

Summary

objects/userSavePhoto.php is a legacy profile-photo endpoint that accepts a base64 POST parameter and writes the decoded bytes to videos/userPhoto/photo<users_id>.png. Its only access control is User::isLogged(). It does not end in .json.php, so it is excluded from the project's global autoCSRFGuard (which is suffix-scoped in objects/include_config.php). There is no CSRF token, no Origin/Referer check, and no MIME validation of the decoded bytes. Because AVideo's default cookie policy is SameSite=None; Secure on HTTPS (objects/functionsPHP.php:227), an attacker who lures a logged-in user to a malicious page can overwrite that user's profile photo with arbitrary bytes and also triggers a site-wide clearCache(true) on every forged request.

Details

Handler (objects/userSavePhoto.php, 51 lines total):

php
// line 12 - only access control
if (!User::isLogged()) {
    $obj->msg = __("You must be logged");
    die(json_encode($obj));
}
// ...
// line 29 - unvalidated base64 from POST
$fileData = base64DataToImage($_POST['imgBase64']);
// line 30 - deterministic filename tied to the VICTIM's session
$fileName = 'photo'. User::getId().'.png';
$photoURL = $imagePath.$fileName;
// line 35 - raw bytes written to disk
$bytes = file_put_contents($global['systemRootPath'].$photoURL, $fileData);
// lines 43-48 - DB update + global cache invalidation unconditionally
$user = new User(User::getId());
$user->setPhotoURL($photoURL);
if ($user->save()) {
    User::deleteOGImage(User::getId());
    User::updateSessionInfo();
    clearCache(true);
}

base64DataToImage (objects/functionsImages.php:1026) performs no content validation:

php
function base64DataToImage($imgBase64) {
    $img = $imgBase64;
    $img = str_replace('data:image/png;base64,', '', $img);
    $img = str_replace(' ', '+', $img);
    return base64_decode($img);
}

There is no call to getimagesizefromstring, imagecreatefromstring, or MIME detection. Arbitrary bytes up to post_max_size are accepted.

Why the global CSRF guard does not apply. objects/include_config.php (around line 314) only invokes autoCSRFGuard when the script filename matches *.json.php:

php
if (... $_SERVER['REQUEST_METHOD'] === 'POST' &&
    substr($baseName, -9) === '.json.php') {
    autoCSRFGuard($baseName, $_SERVER['SCRIPT_FILENAME']);
}

userSavePhoto.php is missing the .json.php suffix, so neither autoCSRFGuard nor forbidIfIsUntrustedRequest runs. There is no explicit call to any of these in the file (verified by grep: no getCSRF, no forbidIfIsUntrustedRequest, no HTTP_ORIGIN, no HTTP_REFERER). Routing rewrites in .htaccess also expose this handler as /savePhoto.

Why the victim's cookie is sent cross-origin. objects/functionsPHP.php:227:

php
function _getCookieSameSiteValue($secure) {
    return $secure ? 'None' : 'Lax';
}

On HTTPS (the expected deployment), session cookies default to SameSite=None; Secure, which browsers attach to cross-site POSTs. A plain application/x-www-form-urlencoded form POST is a "simple request" under CORS rules and does not trigger a preflight, so the browser sends the POST and its cookie without the server having to opt in.

PoC

  1. Victim logs into the AVideo instance (e.g., https://victim.example.com). PHPSESSID is set with SameSite=None; Secure.
  2. Attacker hosts the following HTML on any domain:
html
<!doctype html>
<html><body>
<form id="f" action="https://victim.example.com/objects/userSavePhoto.php" method="POST">
  <!-- Any bytes: here, 'HELLO WORLD' base64-encoded -->
  <input name="imgBase64" value="SEVMTE8gV09STEQ=">
</form>
<script>document.forms[0].submit();</script>
</body></html>
  1. Victim visits the attacker page in the same browser. The form auto-submits. The browser sends the POST with the victim's session cookie.
  2. userSavePhoto.php passes the User::isLogged() check, decodes the base64, and writes the raw bytes to videos/userPhoto/photo<VICTIM_USERS_ID>.png. It also calls $user->save(), User::deleteOGImage(), User::updateSessionInfo(), and clearCache(true).
  3. Fetching https://victim.example.com/videos/userPhoto/photo<VICTIM_USERS_ID>.png (the file is now the attacker's bytes - HELLO WORLD in this test case). The response is 200 OK and the body equals the submitted bytes.

Replace the imgBase64 payload with a valid PNG to make the defacement visually persuasive, or with up to ~6 MB of any bytes to force a large write.

Impact

  • Integrity - profile defacement of any logged-in user. One click lets an attacker replace a victim's profile photo with arbitrary bytes: offensive imagery, misleading branding, or a clone of another user's photo for impersonation. The file path is deterministic (photo<users_id>.png), so the attacker can later direct others to the overwritten URL.
  • Availability - global cache thrash. Every successful forged request calls clearCache(true), invalidating application-wide caches. Repeatedly tricking logged-in users into visiting the attacker page (e.g., by including the payload as a hidden iframe on a popular site) produces sustained cache invalidation.
  • Availability - disk pressure. With no size cap beyond PHP's post_max_size (default 8 MB → ~6 MB after base64 decode), each forged submission writes a multi-megabyte file. Across many victims this enables distributed disk exhaustion.
  • No confidentiality impact and no code execution (files are served with Content-Type: image/png based on extension, so SVG-with-script payloads are not interpreted).
  • Related endpoints. objects/userSaveBackground.php exhibits the same pattern (same base64DataToImage sink, same lack of CSRF/Origin/MIME checks) and is exploitable identically; fix should be applied consistently.

Recommended Fix

Apply the existing same-origin guard that protects the *.json.php endpoints and add content validation. In objects/userSavePhoto.php, immediately after the login check:

php
require_once $global['systemRootPath'] . 'objects/functionsSecurity.php';
forbidIfIsUntrustedRequest('userSavePhoto');

$raw = $_POST['imgBase64'] ?? '';
if (strlen($raw) > 2 * 1024 * 1024) { // ~1.5 MB decoded cap
    $obj->msg = __('Image too large');
    die(json_encode($obj));
}
$fileData = base64DataToImage($raw);
if ($fileData === false || $fileData === '' || @imagecreatefromstring($fileData) === false) {
    $obj->msg = __('Invalid image');
    die(json_encode($obj));
}

The longer-term fix is to broaden the global guard in objects/include_config.php so that autoCSRFGuard covers every authenticated POST handler, not only those whose filenames end in .json.php - the current suffix-based gating is a footgun that silently excludes legacy endpoints like userSavePhoto.php and userSaveBackground.php. Also consider moving the clearCache(true) call inside the if ($bytes) branch so that zero-byte writes do not invalidate the global cache.

AnalysisAI

Cross-site request forgery in AVideo's userSavePhoto.php endpoint allows unauthenticated remote attackers to overwrite any logged-in user's profile photo with arbitrary bytes by luring them to a malicious webpage. The vulnerability exploits a missing CSRF token and a default cookie policy of SameSite=None on HTTPS deployments, combined with unvalidated base64 decoding that accepts any file content. Each successful attack also triggers a global cache invalidation, enabling denial-of-service via cache thrashing.

Technical ContextAI

AVideo's legacy profile photo handler (objects/userSavePhoto.php) decodes base64-encoded POST data and writes it directly to disk without validation. The underlying function base64DataToImage() in objects/functionsImages.php performs only string replacement (removing data URIs and normalizing whitespace) before base64_decode(), with no MIME type validation or image format verification. The endpoint lacks the .json.php suffix that would trigger AVideo's global autoCSRFGuard in objects/include_config.php (line 314), which selectively protects only handlers matching *.json.php. Additionally, the application's default session cookie configuration sets SameSite=None; Secure on HTTPS (per objects/functionsPHP.php:227), allowing browsers to attach the session cookie to cross-origin POST requests without preflight checks. The deterministic filename (photo<user_id>.png) tied to the victim's session ID means an attacker can predictably overwrite a specific user's image and trigger subsequent clearCache(true) calls that invalidate application-wide caches.

RemediationAI

Apply the patch from commit 9c38468041505e637101c5943c5370c68f48e3ac immediately, which adds the missing forbidIfIsUntrustedRequest() call to reject cross-origin requests, implements image format validation via getimagesizefromstring() and magic byte detection, and enforces a 2 MB decoded file size limit. If a tagged release incorporating this commit is available, upgrade to it; otherwise, apply the commit directly or cherry-pick the changes into objects/userSavePhoto.php, objects/userSaveBackground.php, and objects/functionsImages.php. The patch adds four new validation functions: normalizeBase64ImageData(), estimateBase64DecodedSize(), isValidImageBinaryData(), and getValidatedImageBinaryFromBase64(), which replace direct calls to the unvalidated base64DataToImage() function. As a temporary compensating control pending patch deployment, block HTTP POST requests to /objects/userSavePhoto.php and /objects/userSaveBackground.php at the web server level (nginx/Apache) if these endpoints are not critical for your use case, or restrict access to same-origin requests only using X-Frame-Options: DENY and explicit Origin header validation. Note that the remediation also defers clearCache(true) invocation to occur only after successful file writes (if ($bytes) branch), preventing cache thrashing from zero-byte uploads. Verify that the patched version is deployed to all production and staging instances, and review any custom endpoints that accept base64-encoded file uploads to ensure they implement equivalent validation.

More in PHP

View all
CVE-2012-1823 CRITICAL POC
9.8 May 11

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

CVE-2016-1555 CRITICAL POC
9.8 Apr 21

(1) boardData102.php, (2) boardData103.php, (3) boardDataJP.php, (4) boardDataNA.php, and (5) boardDataWW.php in Netgear

CVE-2024-11680 CRITICAL POC
9.8 Nov 26

ProjectSend versions prior to r1720 are affected by an improper authentication vulnerability. Rated critical severity (C

CVE-2025-49113 CRITICAL POC
9.9 Jun 02

Roundcube Webmail contains a critical PHP object deserialization vulnerability (CVE-2025-49113, CVSS 9.9) that allows au

CVE-2017-9841 CRITICAL POC
9.8 Jun 27

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

CVE-2025-0108 HIGH POC
8.8 Feb 12

Palo Alto Networks PAN-OS management web interface contains an authentication bypass allowing unauthenticated attackers

CVE-2021-25298 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2021-25296 HIGH POC
8.8 Feb 15

Nagios XI version xi-5.7.5 is affected by OS command injection. Rated high severity (CVSS 8.8), this vulnerability is re

CVE-2013-4983 CRITICAL POC
10.0 Sep 10

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

CVE-2023-6553 CRITICAL POC
9.8 Dec 15

The Backup Migration plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 1

CVE-2024-46506 CRITICAL POC
10.0 May 13

NetAlertX (formerly PiAlert) versions 23.01.14 through 24.x before 24.10.12 allow unauthenticated command injection thro

CVE-2024-8353 CRITICAL POC
9.8 Sep 28

The GiveWP - Donation Plugin and Fundraising Platform plugin for WordPress is vulnerable to PHP Object Injection in all

Share

CVE-2026-43877 vulnerability details – vuln.today

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