CVE-2026-25315

hCaptcha for WP <= 4.22.0 - Missing Authorization

mediumMissing Authorization
5.3
CVSS Score
5.3
CVSS Score
medium
Severity
4.23.0
Patched in
99d
Time to patch

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:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Unchanged
None
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=4.22.0
PublishedJanuary 26, 2026
Last updatedMay 4, 2026

What Changed in the Fix

Changes introduced in v4.23.0

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

# 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 (likely hcap_fst_issue_token).
  • Parameters:
    • action: The value of HCaptchaFSTObject.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

  1. Frontend Script: assets/js/hcaptcha-fst.js is enqueued on pages containing hCaptcha-protected forms.
  2. JS Initialization: The script fst.init() listens for hCaptchaLoaded.
  3. Token Request: The getToken() function (line 46) is triggered.
  4. AJAX Call: It constructs a URLSearchParams object (lines 52-53):
    formBody.set( 'action', HCaptchaFSTObject.issueTokenAction );
    formBody.set( 'postId', postId );
    
  5. Submission: It performs a fetch request to HCaptchaFSTObject.ajaxUrl (line 55) without any nonce or authentication headers.
  6. Vulnerable Sink: The PHP function registered to the issueTokenAction returns 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:

  1. Identify a page where hCaptcha is active (e.g., the homepage or a specific post).
  2. Use browser_eval to extract the localization object:
    browser_eval("window.HCaptchaFSTObject")
  3. Extract the issueTokenAction value 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 (where postId can 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

  1. Install and activate "hCaptcha for WP" <= 4.22.0.
  2. Configure hCaptcha with Site Key and Secret (use test keys if necessary).
  3. Enable hCaptcha for "WordPress Comment Form".
  4. Ensure a post exists (e.g., ?p=1) where comments are open.
  5. 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.php should return a 200 OK response with a JSON body similar to:
    {"success":true,"data":{"token":"[32-64_char_alphanumeric_string]"}}
  • Submitting a comment with this token in the hcap_fst_token field should succeed even if the h-captcha-response field is empty or missing.

8. Verification Steps

  1. Check Comment Status: Use WP-CLI to verify the comment was created:
    wp comment list --post_id=1 --status=approve
  2. Verify Nonce Absence: Confirm that repeating the http_request from Step 2 works without any _wpnonce or cookie headers.

9. Alternative Approaches

  • Registration Bypass: If comments are closed, test against the registration form (/wp-login.php?action=register). The hcap_fst_token should work there as well.
  • Variable Inspection: If HCaptchaFSTObject is not defined, search the HTML source for hcaptcha-fst-js-extra which is the standard WordPress ID for localized scripts.
  • Parameter Variation: Try the request without postId to see if it's mandatory; if the plugin uses it to generate a post-specific token, the exploit may require matching the postId of the target form.
Research Findings
Static analysis — not yet PoC-verified

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

diff -ru /home/deploy/wp-safety.org/data/plugin-versions/hcaptcha-for-forms-and-more/4.22.0/assets/css/settings-base.css /home/deploy/wp-safety.org/data/plugin-versions/hcaptcha-for-forms-and-more/4.23.0/assets/css/settings-base.css
--- /home/deploy/wp-safety.org/data/plugin-versions/hcaptcha-for-forms-and-more/4.22.0/assets/css/settings-base.css	2025-11-30 21:59:12.000000000 +0000
+++ /home/deploy/wp-safety.org/data/plugin-versions/hcaptcha-for-forms-and-more/4.23.0/assets/css/settings-base.css	2026-02-08 07:52:14.000000000 +0000
@@ -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.