WP Forms Connector <= 1.8 - Missing Authorization to Unauthenticated Information Exposure via 'user/list' REST Endpoint
Description
The WP Forms Connector plugin for WordPress is vulnerable to Information Exposure in all versions up to, and including, 1.8. The plugin registers the REST route wp/v3/user/list/<id> (callback userDetail()) with permission_callback set to '__return_true', and the function's home-grown authentication only verifies that the supplied 'Username' HTTP header maps to an administrator account and that a 'Password' HTTP header is non-empty. It never validates the password with wp_check_password() (unlike the sibling delete_wc_user() function which does). This makes it possible for unauthenticated attackers to retrieve sensitive information for any registered user ID — including the WordPress password hash (user_pass) and email address — by sending a request with a valid administrator login name (commonly the default 'admin') and any arbitrary password value.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:NTechnical Details
<=1.8# Exploitation Research Plan: CVE-2026-9178 (WP Forms Connector) ## 1. Vulnerability Summary The **WP Forms Connector** plugin (<= 1.8) for WordPress suffers from a critical information exposure vulnerability due to a flawed "home-grown" authentication mechanism in its REST API implementation. The …
Show full research plan
Exploitation Research Plan: CVE-2026-9178 (WP Forms Connector)
1. Vulnerability Summary
The WP Forms Connector plugin (<= 1.8) for WordPress suffers from a critical information exposure vulnerability due to a flawed "home-grown" authentication mechanism in its REST API implementation. The plugin registers a custom REST route wp/v3/user/list/<id> designed to provide user details. While it implements a check for a Username and Password header, it only verifies that the provided Username belongs to an administrator and that the Password header is not empty. It fails to call wp_check_password() to validate the password's correctness. Because the permission_callback is set to __return_true, the endpoint is publicly accessible, allowing unauthenticated attackers to dump sensitive user data, including WordPress password hashes and email addresses.
2. Attack Vector Analysis
- Endpoint:
/wp-json/wp/v3/user/list/<id>(where<id>is the target user's ID). - Method:
GET(Inferred based on standard REST "list" and "detail" patterns described). - Vulnerable Function:
userDetail()(callback for the route). - Required Headers:
Username: A valid administrator login name (e.g.,admin).Password: Any non-empty string (e.g.,pwned).
- Authentication Level: Unauthenticated.
- Preconditions:
- Knowledge of at least one administrator's username (standard WordPress reconnaissance).
- The plugin must be active.
3. Code Flow
- Registration: The plugin uses
register_rest_routeduringrest_api_init.- Route:
wp/v3/user/list/(?P<id>[\d]+) - Callback:
userDetail - Permission Callback:
__return_true
- Route:
- Request Handling: An attacker sends a request to the endpoint.
- Authentication Bypass:
userDetail()retrieves theUsernameandPasswordheaders.- It looks up the user by
Usernameusingget_user_by( 'login', $username ). - It checks if this user has the
administratorcapability/role. - It checks
if ( ! empty( $password ) ). - The Flaw: Crucially, it skips
wp_check_password( $password, $user->user_pass, $user->ID ).
- Data Extraction: The function retrieves the user object for the requested
<id>viaget_userdata( $id ). - Sink: The function returns the entire user object or a subset including
user_passanduser_emailin a JSON response.
4. Nonce Acquisition Strategy
According to the vulnerability description, the permission_callback for this route is set to __return_true.
- Result: No WordPress REST API nonce (
_wpnonce) is required for unauthenticated access. - The "authentication" is entirely handled within the
userDetailfunction via custom HTTP headers, bypassing the standard WordPress REST authentication cookies and nonces.
5. Exploitation Strategy
The exploit will attempt to retrieve the password hash of the primary administrator (ID 1) by spoofing an admin request.
Step 1: Identify Admin Username
Use the http_request tool to check for common admin usernames if not already known.
- Request:
GET /wp-json/wp/v2/users - Target: Look for users with the role "administrator" or ID 1.
Step 2: Perform the Information Leak
Send the malicious request to the vulnerable endpoint.
- Tool:
http_request - Method:
GET - URL:
http://localhost:8080/wp-json/wp/v3/user/list/1 - Headers:
Username: admin Password: arbitrary_value Accept: application/json
Step 3: Parse the Response
The expected response is a JSON object. We will specifically look for the user_pass field.
6. Test Data Setup
To verify the exploit in the test environment:
- Users: Ensure at least one administrator exists with the username
admin. - Plugin: Install and activate
wp-forms-connectorversion 1.8. - Target: Ensure there is a user with ID 1 (standard for first admin).
7. Expected Results
A successful exploit will return an HTTP 200 OK with a JSON body similar to:
{
"ID": "1",
"user_login": "admin",
"user_pass": "$P$By6E...[REDACTED]...",
"user_email": "admin@example.com",
"user_registered": "2023-10-27 10:00:00"
}
If the exploit fails, the response might be a 401/403 or an error message indicating invalid credentials (if the headers are missing or the username is incorrect).
8. Verification Steps
After performing the HTTP request, verify the leaked data against the actual database state using WP-CLI:
# Get the actual hash from the database
wp user get 1 --field=user_pass
# Compare the hash returned by the http_request tool with this value.
9. Alternative Approaches
- ID Enumeration: If ID 1 is not the target, use a loop/intruder-style approach to request IDs 1 through 100 to dump the entire user database.
- Username Discovery: If
adminis not the username, trymanager,webmaster, or use thewp/v2/usersendpoint to find valid login names. - Endpoint Variation: If
GETfails, attempt aPOSTrequest to the same endpoint with the same headers, as some REST handlers are permissive with methods.
Summary
The WP Forms Connector plugin for WordPress exposes sensitive user data, including password hashes and email addresses, via an insecure custom REST API endpoint. The vulnerability occurs because the plugin's internal authentication logic only checks if a provided 'Username' belongs to an administrator and if a 'Password' header is non-empty, without actually validating the password's correctness.
Vulnerable Code
// In rest route registration register_rest_route( 'wp/v3', '/user/list/(?P<id>[\d]+)', array( 'methods' => 'GET', 'callback' => 'userDetail', 'permission_callback' => '__return_true', ) ); --- // In callback function userDetail() function userDetail( $data ) { $id = $data['id']; $username = $_SERVER['HTTP_USERNAME']; $password = $_SERVER['HTTP_PASSWORD']; $user = get_user_by( 'login', $username ); if ( $user && in_array( 'administrator', (array) $user->roles ) ) { // The vulnerability: verifies password is not empty, but does not call wp_check_password() if ( ! empty( $password ) ) { return get_userdata( $id ); } } }
Security Fix
@@ -20,1 +20,1 @@ - 'permission_callback' => '__return_true', + 'permission_callback' => function() { return current_user_can('manage_options'); }, @@ -35,1 +35,1 @@ - if ( ! empty( $password ) ) { + if ( ! empty( $password ) && wp_check_password( $password, $user->user_pass, $user->ID ) ) {
Exploit Outline
The exploit targets the '/wp-json/wp/v3/user/list/<id>' endpoint using a GET request. The attacker must provide two custom HTTP headers: 'Username', containing the login name of a valid WordPress administrator (e.g., 'admin'), and 'Password', containing any arbitrary non-empty string. Because the 'permission_callback' is set to return true and the function fails to verify the password hash using wp_check_password(), the endpoint returns the full user object for the specified ID, including the 'user_pass' hash and 'user_email'.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.