[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fFcavVWVv7UFUVJNqHtAixMz_fkgkf4Jsq_gH-08LTwE":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":9,"severity":11,"cvss_score":12,"cvss_vector":13,"vuln_type":14,"published_date":15,"updated_date":16,"references":17,"days_to_patch":9,"patch_diff_files":19,"patch_trac_url":9,"research_status":20,"research_verified":21,"research_rounds_completed":22,"research_plan":23,"research_summary":24,"research_vulnerable_code":9,"research_fix_diff":25,"research_exploit_outline":26,"research_model_used":27,"research_started_at":28,"research_completed_at":29,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":21,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":21,"source_links":30},"CVE-2026-14495","dologin-security-unauthenticated-authentication-bypass-via-insufficient-randomness-via-dologin-parameter-weak-prng-token","DoLogin Security \u003C= 4.3 - Unauthenticated Authentication Bypass via Insufficient Randomness via 'dologin' Parameter Weak PRNG Token","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=\u003Cid>.\u003Chash>` 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.","dologin",null,"\u003C=4.3","high",8.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Use of Cryptographically Weak Pseudo-Random Number Generator (PRNG)","2026-07-07 16:39:40","2026-07-08 05:34:07",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F16bce371-b524-48eb-8537-3f9df802abd3?source=api-prod",[],"researched",false,3,"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.\n\n### Security Analysis: Weak PRNG and Authentication Bypass\n\nThe vulnerability described (CVE-2026-14495) illustrates three critical security failures common in legacy or poorly implemented authentication systems:\n\n#### 1. Insufficient Entropy in PRNG Seeding\nThe use of `mt_srand((double) microtime() * 1000000)` to seed a Pseudo-Random Number Generator (PRNG) is a classic security flaw. \n*   **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). \n*   **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.\n\n#### 2. Non-Constant-Time Comparison\nUsing standard equality operators like `!=` or `==` for sensitive tokens introduces timing vulnerabilities.\n*   **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.\n*   **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.\n\n#### 3. Authentication Hook Bypass\nRegistering 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.\n\n---\n\n### Remediation and Secure Implementation\n\nTo securely implement \"magic links\" or passwordless login in WordPress, developers should follow these practices:\n\n#### Cryptographically Secure Token Generation\nUse PHP 7+ native functions designed for security. `random_bytes()` generates cryptographically strong pseudo-random bytes.\n\n```php\n\u002F\u002F Generate a secure 32-byte token\n$token = bin2hex(random_bytes(32));\n\n\u002F\u002F Store the hash of the token in the database, not the token itself\n$token_hash = wp_hash($token); \n```\n\n#### Constant-Time Verification\nAlways use `hash_equals()` to compare tokens. This function takes the same amount of time regardless of whether the strings match, preventing timing attacks.\n\n```php\nif ( hash_equals( $stored_hash, wp_hash( $user_provided_token ) ) ) {\n    \u002F\u002F Valid token\n}\n```\n\n#### Proper Authentication Flow\nInstead of calling `wp_set_auth_cookie()` directly, ensure that the process respects WordPress security best practices, including:\n*   **Expiration:** Set a short lifespan for magic links (e.g., 15–60 minutes).\n*   **Single Use:** Delete or invalidate the token immediately after a successful (or failed) use.\n*   **Rate Limiting:** Implement strict rate limiting on the endpoint to prevent brute-forcing of the link ID or the token.\n*   **Standard Hooks:** Use the `authenticate` filter to integrate with the WordPress login system, ensuring that other security plugins can monitor and protect the process.\n\nFor further information on secure WordPress development, I recommend reviewing the [WordPress Plugin Handbook's Security section](https:\u002F\u002Fdeveloper.wordpress.org\u002Fplugins\u002Fsecurity\u002F).","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.","--- a\u002Fdologin.php\n+++ b\u002Fdologin.php\n@@ -1,10 +1,4 @@\n public static function rrand($length = 32) {\n-    mt_srand((double) microtime() * 1000000);\n-    $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';\n-    $str = '';\n-    for ($i = 0; $i \u003C $length; $i++) {\n-        $str .= $chars[mt_rand(0, strlen($chars) - 1)];\n-    }\n-    return $str;\n+    return bin2hex(random_bytes($length \u002F 2));\n }\n\n--- a\u002Fincludes\u002Fpswdless.php\n+++ b\u002Fincludes\u002Fpswdless.php\n@@ -10,7 +10,7 @@\n         list($id, $hash) = explode('.', $_GET['dologin']);\n         $stored_hash = get_user_meta($id, '_dologin_hash', true);\n-        if ($hash != $stored_hash) {\n+        if (!hash_equals($stored_hash, $hash)) {\n             return;\n         }","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.","gemini-3-flash-preview","2026-07-25 08:37:21","2026-07-25 08:38:35",{"type":31,"vulnerable_version":9,"fixed_version":9,"vulnerable_browse":9,"vulnerable_zip":9,"fixed_browse":9,"fixed_zip":9,"all_tags":32},"plugin","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fdologin\u002Ftags"]