If you have been following WordPress security news this week, you might have noticed something: two of the three critical vulnerabilities patched between April 24 and May 2 involve PHP type confusion. The Temporary Login auth bypass (CVE-2026-7567) uses an array input to fool empty(). The PickPlugins User Verification bypass (CVE-2026-7458) uses loose comparison to bypass OTP checks.
This is not random. PHP’s type system is flexible — and flexible systems are exploitable. Here is how the trick works, why it keeps showing up, and how to defend against it.
What Is PHP Type Confusion?
PHP is a dynamically typed language. Variables can change types freely, and many built-in functions behave differently depending on what type they receive. This is convenient for developers but dangerous for security.
The most common type confusion patterns in WordPress plugin vulnerabilities are:
- Array as string — Pass an array parameter where a string is expected
- Type juggling — Exploit PHP’s loose comparison (
==) instead of strict (===) - Mixed-type function behavior — Functions that handle arrays and scalars differently
The Array Trick: CVE-2026-7567
Consider this simplified version of the vulnerable code from the Temporary Login plugin:
function maybe_login_temporary_user() {
if (!empty($_GET['temp-login-token'])) {
$token = sanitize_key($_GET['temp-login-token']);
$users = get_users(array(
'meta_key' => '_temporary_login_token',
'meta_value' => $token
));
if (!empty($users)) {
wp_set_current_user($users[0]->ID);
wp_set_auth_cookie($users[0]->ID);
}
}
}At first glance, the code looks fine. It checks that the token is not empty, sanitizes it, looks up a user with that token, and logs them in. But the devil is in the details.
Step 1: Bypassing empty()
PHP’s empty() function has a peculiar behavior: it returns false (meaning “not empty”) for an empty array. From PHP’s perspective, an array exists as a value even if it has no elements. When the attacker sends:
GET /?temp-login-token[]=anythingPHP converts the parameter to array('anything'). This is not “empty” in PHP’s eyes, so empty() returns false, and the code proceeds.
Step 2: sanitize_key() Returns an Empty String
WordPress’s sanitize_key() function expects a string. When given an array, it performs some processing, but the end result is an empty string. The variable $token becomes ''.
Step 3: get_users() Ignores Empty meta_value
WordPress’s get_users() function treats an empty meta_value parameter as “no filter on value” — it only filters by meta_key. This means it returns all users with the meta_key _temporary_login_token, regardless of their actual token value. The attacker is logged in as the first user returned.
The Type Juggling Trick: CVE-2026-7458
The PickPlugins User Verification vulnerability uses a different type confusion angle. The OTP validation code uses PHP’s loose comparison:
if ($otp_from_user == $otp_from_database) {
// OTP matched - log the user in
}With == (loose) instead of === (strict), PHP performs type juggling before comparing. Under specific conditions, passing a boolean true as the OTP value will match against a numeric database value. This is why the CVE description specifies that sending true as the OTP bypasses authentication entirely.
Why This Keeps Happening
PHP type confusion vulnerabilities have been responsible for some of the most impactful WordPress plugin CVEs in recent years. The pattern repeats because:
- PHP’s built-in functions silently handle unexpected types instead of throwing errors
- Developer assumptions — most developers assume GET/POST parameters are always strings
- Testing gaps — sending an array where a string is expected is almost never tested
- Legacy code — PHP 8+ has better type enforcement, but most WordPress plugins support PHP 7.x
How to Write PHP Code That Resists Type Confusion
- Validate input types explicitly — Use
is_string()oris_array()to verify parameter types before processing:if (!isset($_GET['token']) || !is_string($_GET['token'])) { return; } - Use strict comparison — Always prefer
===and!==over==and!=, especially for authentication-related checks - Type-hint your functions — PHP 7+ supports scalar type hints:
function processToken(string $token): void - Declare strict types — Start your PHP files with
declare(strict_types=1);to enforce type strictness - Cast early — Cast $_GET parameters to their expected type immediately:
$token = (string) ($_GET['token'] ?? '');
How Trusti Security Helps
Trusti Security provides real-time monitoring of your WordPress site’s plugin inventory. When a vulnerability is published for any of your installed plugins, you receive an immediate alert with the CVE details, severity, and recommended action — often before the exploit becomes widely known.
Additionally, our Trusti Radar browser extension helps you assess the security posture of any WordPress site you visit, showing installed plugins and known vulnerabilities at a glance.
Summary
PHP type confusion is not going away. As long as WordPress plugins process user input with PHP’s flexible type system, attackers will find ways to slip arrays where strings belong and true where integers are expected. The defense is simple but requires discipline: validate types explicitly, compare strictly, and never assume the input is what you expect.
Stay safe out there.