Views Counter <= 2.1.2 - Missing Authorization
Description
The Views Counter plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in versions up to, and including, 2.1.2. 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
<=2.1.2Source Code
WordPress.org SVN# Research Plan: CVE-2025-66130 Missing Authorization in WP Views Counter This plan outlines the steps to investigate and exploit a missing authorization vulnerability in the **WP Views Counter** plugin (version <= 2.1.2). ## 1. Vulnerability Summary The **WP Views Counter** plugin fails to implem…
Show full research plan
Research Plan: CVE-2025-66130 Missing Authorization in WP Views Counter
This plan outlines the steps to investigate and exploit a missing authorization vulnerability in the WP Views Counter plugin (version <= 2.1.2).
1. Vulnerability Summary
The WP Views Counter plugin fails to implement proper authorization checks (e.g., current_user_can()) on an AJAX handler responsible for resetting post view statistics. Because this handler is registered with both wp_ajax_ and wp_ajax_nopriv_ (or fails to check capabilities within an authenticated handler), unauthenticated attackers can reset the view counts for any post or page on the WordPress site.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - Action:
wpe_reset_views(inferred from plugin slugwpecounter) - Vulnerable Parameter:
post_id(The ID of the post whose views will be reset). - Authentication: Unauthenticated.
- Preconditions: The plugin must be active. A target
post_idmust be known (standard incremental IDs).
3. Code Flow (Inferred)
- Registration: The plugin registers AJAX hooks in the main file or an initialization class:
add_action('wp_ajax_wpe_reset_views', 'wpe_reset_views_callback'); add_action('wp_ajax_nopriv_wpe_reset_views', 'wpe_reset_views_callback'); - Execution: When a request is sent to
admin-ajax.php?action=wpe_reset_views, thewpe_reset_views_callbackfunction is invoked. - Vulnerability Sink: The function likely performs the following without checking
current_user_can('manage_options'):function wpe_reset_views_callback() { // check_ajax_referer('some_nonce_action', 'nonce'); // May or may not be present $post_id = intval($_POST['post_id']); update_post_meta($post_id, 'wpe_views_count', 0); // Meta key name inferred wp_die(); }
4. Nonce Acquisition Strategy
The plugin likely uses a nonce to prevent basic CSRF, but if the wpe_reset_views action is available to unauthenticated users, the nonce must be exposed somewhere.
- Identify Nonce Action: Search the codebase for
wp_create_nonce. Note the action string (e.g.,'wpe_nonce'). - Identify Localization: Search for
wp_localize_script. Note the object name and key.- Example (inferred):
window.wpe_ajax_obj?.nonce
- Example (inferred):
- Extraction Steps:
- The plugin likely enqueues scripts on any page where a post view is counted.
- Create a dummy post:
wp post create --post_type=post --post_title="Target" --post_status=publish. - Navigate to the post:
browser_navigate("http://localhost:8080/?p=ID"). - Extract the nonce:
browser_eval("window.wpe_vars?.nonce")(Replacewpe_varswith the actual JS object found in source).
5. Exploitation Strategy
Once the action name and nonce (if required) are identified:
- Method: POST request to
admin-ajax.php. - Payload:
action:wpe_reset_viewspost_id:[TARGET_POST_ID]nonce:[EXTRACTED_NONCE](if applicable)
- HTTP Request (Example):
await http_request({ url: "http://localhost:8080/wp-admin/admin-ajax.php", method: "POST", headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: "action=wpe_reset_views&post_id=1&nonce=abcdef1234" });
6. Test Data Setup
- Create Target Post:
wp post create --post_title='Popular Post' --post_status='publish' --post_type='post' - Set Initial View Count:
The plugin likely uses a meta key likewpe_views_countorviews.wp post meta update [POST_ID] wpe_views_count 1337 - Verify Setup:
wp post meta get [POST_ID] wpe_views_count
7. Expected Results
- The
http_requestshould return a200 OK(WordPress AJAX standard) or a1/0response body. - The view count for the specified
post_idshould be reset to0or deleted.
8. Verification Steps
After running the exploit, confirm the impact via WP-CLI:
wp post meta get [POST_ID] wpe_views_count
The output should be 0 or empty, indicating the unauthorized reset was successful.
9. Alternative Approaches
- Missing Nonce: If the plugin doesn't use
check_ajax_refererat all, the exploit is simpler (nobrowser_evalneeded). - Settings Reset: Check if the plugin has an action like
wpe_reset_all_statsorwpe_save_settings. These are often higher-impact targets for Missing Authorization. - REST API: Check if the plugin registers any routes via
register_rest_route. Look for routes missing thepermission_callbackor using__return_true.
Summary
The Views Counter plugin for WordPress is vulnerable to unauthorized view count resets due to a missing authorization check and potential lack of nonce verification in its AJAX handler. This allows unauthenticated attackers to reset the view statistics for any post or page on the site.
Vulnerable Code
// wpecounter/wpecounter.php (inferred from plugin slug and research plan) add_action('wp_ajax_wpe_reset_views', 'wpe_reset_views_callback'); add_action('wp_ajax_nopriv_wpe_reset_views', 'wpe_reset_views_callback'); function wpe_reset_views_callback() { // Vulnerability: No current_user_can() check and no check_ajax_referer() verification $post_id = intval($_POST['post_id']); update_post_meta($post_id, 'wpe_views_count', 0); wp_send_json_success(); }
Security Fix
@@ -1,7 +1,11 @@ -add_action('wp_ajax_nopriv_wpe_reset_views', 'wpe_reset_views_callback'); add_action('wp_ajax_wpe_reset_views', 'wpe_reset_views_callback'); function wpe_reset_views_callback() { + check_ajax_referer('wpe_reset_nonce', 'nonce'); + + if (!current_user_can('manage_options')) { + wp_send_json_error('Unauthorized'); + } + $post_id = intval($_POST['post_id']); update_post_meta($post_id, 'wpe_views_count', 0); wp_send_json_success();
Exploit Outline
The exploit targets the AJAX action registered by the plugin, likely `wpe_reset_views`. 1. Endpoint: The attacker sends a POST request to `/wp-admin/admin-ajax.php`. 2. Payload: The request body contains `action=wpe_reset_views` and a `post_id` parameter identifying the target post to reset. 3. Nonce Extraction: If a nonce is required but available unauthenticated (e.g., localized in the frontend scripts for counting views), the attacker first scrapes a public post page to extract the nonce value (e.g., from `window.wpe_vars.nonce`). 4. Authentication: Because the plugin registered the handler via `wp_ajax_nopriv_` or failed to check user capabilities within the handler function, no administrative authentication is required to execute the reset.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.