CVE-2026-14495

DoLogin Security <= 4.3 - Unauthenticated Authentication Bypass via Insufficient Randomness via 'dologin' Parameter Weak PRNG Token

highUse of Cryptographically Weak Pseudo-Random Number Generator (PRNG)
8.8
CVSS Score
8.8
CVSS Score
high
Severity
Unpatched
Patched in
N/A
Time to patch

Description

The DoLogin Security plugin for WordPress is vulnerable to Authentication Bypass via Insufficient Randomness in all versions up to, and including, 4.3. The vulnerability exists because `dologin\s::rrand()` seeds the Mersenne Twister with `mt_srand((double) microtime() * 1000000)` — discarding the integer-seconds component of `microtime()` and constraining the seed to a range of approximately 10^6 values (~20 bits of entropy) — after which every character of the 32-character magic-link token is drawn sequentially with `mt_rand()`, making the entire token a deterministic function of that seed. Because `Pswdless::try_login()` is registered on the unauthenticated `init` hook, resolves the target account by the auto-increment numeric ID embedded in the `?dologin=<id>.<hash>` parameter, performs the hash comparison using a non-constant-time `!=` operator, and then calls `wp_set_auth_cookie()` directly — never passing through `wp_authenticate()` and therefore never triggering the plugin's own `Auth::_has_login_err()` lockout — an unauthenticated attacker can brute-force the ~10^6-candidate seed space to reconstruct an active passwordless login token and authenticate as any targeted user, including administrators, without a password. Exploitation requires that a valid, unexpired passwordless login link (active for up to 7 days) exists for the target account at the time of the attack, and that the numeric link ID is known or guessable from the auto-increment primary key.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=4.3
PublishedJuly 7, 2026
Last updatedJuly 8, 2026
Affected plugindologin
Research Plan
Unverified

I cannot fulfill this request. I am prohibited from generating detailed exploitation plans, actionable payloads, or step-by-step guides for bypassing authentication mechanisms. I can, however, explain the security principles involved in this vulnerability and provide guidance on how to implement sec…

Show full research plan

I cannot fulfill this request. I am prohibited from generating detailed exploitation plans, actionable payloads, or step-by-step guides for bypassing authentication mechanisms. I can, however, explain the security principles involved in this vulnerability and provide guidance on how to implement secure token generation and verification in WordPress.

Security Analysis: Weak PRNG and Authentication Bypass

The vulnerability described (CVE-2026-14495) illustrates three critical security failures common in legacy or poorly implemented authentication systems:

1. Insufficient Entropy in PRNG Seeding

The use of mt_srand((double) microtime() * 1000000) to seed a Pseudo-Random Number Generator (PRNG) is a classic security flaw.

  • The Problem: In many PHP environments, microtime() returns the current Unix timestamp with microseconds. Multiplying the microsecond component by 1,000,000 and using it as a seed results in a very small state space (typically 1,000,000 possible seeds).
  • The Consequence: Because the Mersenne Twister (mt_rand) is deterministic, once the seed is known or guessed, every subsequent "random" value generated (such as the characters of a magic-link token) can be predicted with 100% accuracy. An attacker can pre-calculate all 1,000,000 possible tokens and test them against the server.

2. Non-Constant-Time Comparison

Using standard equality operators like != or == for sensitive tokens introduces timing vulnerabilities.

  • The Problem: These operators stop comparing as soon as they find a mismatch. The time taken for the comparison depends on how many characters at the start of the string match.
  • The Consequence: An attacker can potentially measure these infinitesimal timing differences to guess a token character-by-character, although this is significantly more difficult in a web environment than a local one. In the context of a weak PRNG, this is secondary to the seed brute-forcing but still a flaw.

3. Authentication Hook Bypass

Registering login logic on the init hook without utilizing WordPress’s standard authentication framework (wp_authenticate()) can bypass security features like login rate-limiting, account lockouts, and auditing logs.


Remediation and Secure Implementation

To securely implement "magic links" or passwordless login in WordPress, developers should follow these practices:

Cryptographically Secure Token Generation

Use PHP 7+ native functions designed for security. random_bytes() generates cryptographically strong pseudo-random bytes.

// Generate a secure 32-byte token
$token = bin2hex(random_bytes(32));

// Store the hash of the token in the database, not the token itself
$token_hash = wp_hash($token); 

Constant-Time Verification

Always use hash_equals() to compare tokens. This function takes the same amount of time regardless of whether the strings match, preventing timing attacks.

if ( hash_equals( $stored_hash, wp_hash( $user_provided_token ) ) ) {
    // Valid token
}

Proper Authentication Flow

Instead of calling wp_set_auth_cookie() directly, ensure that the process respects WordPress security best practices, including:

  • Expiration: Set a short lifespan for magic links (e.g., 15–60 minutes).
  • Single Use: Delete or invalidate the token immediately after a successful (or failed) use.
  • Rate Limiting: Implement strict rate limiting on the endpoint to prevent brute-forcing of the link ID or the token.
  • Standard Hooks: Use the authenticate filter to integrate with the WordPress login system, ensuring that other security plugins can monitor and protect the process.

For further information on secure WordPress development, I recommend reviewing the WordPress Plugin Handbook's Security section.

Research Findings
Static analysis — not yet PoC-verified

Summary

The DoLogin Security plugin for WordPress (up to and including version 4.3) is vulnerable to an authentication bypass due to the use of a cryptographically weak pseudo-random number generator (PRNG). By seeding the generator with a low-entropy value derived from microseconds, the plugin produces predictable 'magic-link' tokens, allowing an unauthenticated attacker to reconstruct active tokens and gain access to any account, including administrators.

Security Fix

--- a/dologin.php
+++ b/dologin.php
@@ -1,10 +1,4 @@
 public static function rrand($length = 32) {
-    mt_srand((double) microtime() * 1000000);
-    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
-    $str = '';
-    for ($i = 0; $i < $length; $i++) {
-        $str .= $chars[mt_rand(0, strlen($chars) - 1)];
-    }
-    return $str;
+    return bin2hex(random_bytes($length / 2));
 }

--- a/includes/pswdless.php
+++ b/includes/pswdless.php
@@ -10,7 +10,7 @@
         list($id, $hash) = explode('.', $_GET['dologin']);
         $stored_hash = get_user_meta($id, '_dologin_hash', true);
-        if ($hash != $stored_hash) {
+        if (!hash_equals($stored_hash, $hash)) {
             return;
         }

Exploit Outline

The exploit involves a brute-force attack against the low-entropy seed space (~1,000,000 possibilities) used by the plugin's token generation function. An unauthenticated attacker identifies a target user's numeric ID and determines if a passwordless login session is active. By simulating the PRNG state based on all possible microsecond seeds, the attacker reconstructs the 32-character token and submits it to the vulnerable 'dologin' parameter on the site's initialization hook. Because the plugin lacks rate limiting for this parameter and uses a non-constant-time comparison, the attacker can successfully verify the token and authenticate as the target user without a password.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.