Bulk Landing Page Creator for WordPress LPagery <= 2.4.9 - Missing Authorization
Description
The Bulk Page Generator – LPagery plugin for WordPress is vulnerable to unauthorized access due to a missing capability check on a function in all versions up to, and including, 2.4.9. This makes it possible for authenticated attackers, with Contributor-level access and above, to perform an unauthorized action.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:L/A:NTechnical Details
Source Code
WordPress.org SVN# Exploitation Research Plan - CVE-2026-22490 ## 1. Vulnerability Summary **CVE-2026-22490** is a Missing Authorization vulnerability in the **Bulk Page Generator – LPagery** plugin for WordPress (versions <= 2.4.9). The vulnerability exists because the plugin registers several AJAX handlers using …
Show full research plan
Exploitation Research Plan - CVE-2026-22490
1. Vulnerability Summary
CVE-2026-22490 is a Missing Authorization vulnerability in the Bulk Page Generator – LPagery plugin for WordPress (versions <= 2.4.9). The vulnerability exists because the plugin registers several AJAX handlers using the wp_ajax_ hook but fails to perform capability checks (e.g., current_user_can('manage_options')) within the callback functions. This allows any authenticated user with at least Contributor level access to execute administrative actions, such as deleting all pages generated by the plugin or modifying certain plugin settings.
2. Attack Vector Analysis
- Vulnerable Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
lpagery_delete_all_generated(inferred) orlpagery_save_settings(inferred). We will target the deletion of generated pages as the primary PoC. - Payload Parameters:
action:lpagery_delete_all_generated_ajax_nonce: A valid nonce for thelpagery_nonceaction.
- Authentication: Authenticated user with Contributor role.
- Preconditions: The plugin must have been used to generate at least one page, and the Contributor user must be able to obtain a valid nonce.
3. Code Flow
- Entry Point: The user sends a POST request to
/wp-admin/admin-ajax.php. - Hook Registration: The plugin registers the action in its initialization (likely in
includes/class-lpagery.phpor a dedicated AJAX handler file):add_action( 'wp_ajax_lpagery_delete_all_generated', array( $this, 'delete_all_generated_pages' ) ); - Vulnerable Function: The function
delete_all_generated_pages(inferred) is called. - Nonce Check: The function typically calls
check_ajax_referer( 'lpagery_nonce', '_ajax_nonce' );. - Missing Auth Check: The function proceeds to delete pages (e.g., querying for posts with the
_lpagery_generatedmeta key) without checking if the user has themanage_optionscapability. - Sink: Database deletion via
$wpdb->queryorwp_delete_post.
4. Nonce Acquisition Strategy
While LPagery is an admin-focused plugin, it often enqueues its scripts and localizes nonces on all admin pages, or at least on pages accessible to all logged-in users (like the Dashboard).
- Identify Script Localization: Look for
wp_localize_scriptin the plugin source (often inadmin/class-lpagery-admin.php). - Target Variable: Based on common LPagery patterns, the JS object is likely
lpagery_varsorlpagery_obj. - Acquisition Method:
- Log in as the Contributor.
- Navigate to the main WordPress Dashboard:
/wp-admin/index.php. - Use
browser_evalto extract the nonce. - JS Path:
window.lpagery_vars?.nonceorwindow.lpagery_obj?.nonce.
5. Exploitation Strategy
- Setup: Create a Contributor user and generate dummy pages using LPagery (or manually add the meta key to existing pages).
- Nonce Extraction:
- Navigate the browser to
/wp-admin/index.php. - Execute
browser_eval("window.lpagery_vars.nonce")to retrieve the_ajax_nonce.
- Navigate the browser to
- Execution:
- Use
http_requestto send a POST request to the AJAX endpoint. - URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body:
action=lpagery_delete_all_generated&_ajax_nonce=[NONCE]
- Use
- Alternative Action: If deletion is restricted, attempt
action=lpagery_ignore_noticeoraction=lpagery_save_settings.
6. Test Data Setup
- Create Pages:
- Generate 5 pages via the LPagery "Bulk Creator" (if possible via CLI).
- Alternatively, use WP-CLI to create pages with the specific meta key LPagery uses to track its pages:
wp post create --post_type=page --post_title="LPagery Test Page" --post_status=publish --meta_input='{"_lpagery_generated":"1"}'
- Create Attacker:
- Create a contributor:
wp user create attacker attacker@example.com --role=contributor --user_pass=password123.
- Create a contributor:
7. Expected Results
- Response: The
admin-ajax.phpendpoint should return a200 OKresponse, often with a JSON body like{"success":true}or a simple string1. - Impact: All pages created in the "Test Data Setup" phase that have the
_lpagery_generatedmeta key should be moved to the trash or permanently deleted.
8. Verification Steps
- Check Page Existence: Run WP-CLI to count pages with the LPagery meta key:
The count should bewp post list --post_type=page --meta_key=_lpagery_generated --format=count0after a successful exploit. - Check Trash: If the plugin trashes instead of deletes:
wp post list --post_type=page --post_status=trash --meta_key=_lpagery_generated --format=count
9. Alternative Approaches
If lpagery_delete_all_generated is not the vulnerable action:
- Target
lpagery_update_settings: Attempt to change a plugin setting (e.g.,lpagery_capability) tosubscriberorcontributorto grant even more access.- Body:
action=lpagery_update_settings&_ajax_nonce=[NONCE]&option_name=...&option_value=...
- Body:
- Target
lpagery_import_csv: If the plugin allows imports via AJAX, a contributor could potentially create thousands of spam pages or perform a Denial of Service by triggering large imports.
Summary
The LPagery plugin for WordPress (versions up to 2.4.9) is vulnerable to unauthorized access because it fails to perform capability checks in its AJAX handlers. This allows authenticated users with Contributor-level access to trigger administrative actions, such as deleting all generated pages, by providing a valid nonce available in the admin dashboard. The vulnerability stems from relying solely on nonce verification without verifying if the user has appropriate permissions like 'manage_options'.
Vulnerable Code
// In includes/class-lpagery-admin.php (inferred) add_action( 'wp_ajax_lpagery_delete_all_generated', array( $this, 'delete_all_generated_pages' ) ); --- // In includes/class-lpagery-admin.php (inferred) public function delete_all_generated_pages() { // Nonce is checked, but user capability is NOT checked. check_ajax_referer( 'lpagery_nonce', '_ajax_nonce' ); // The function continues to delete pages without checking current_user_can('manage_options') $posts = get_posts(array( 'post_type' => 'any', 'meta_key' => '_lpagery_generated', 'fields' => 'ids', 'posts_per_page' => -1 )); foreach ($posts as $post_id) { wp_delete_post($post_id, true); } wp_send_json_success(); }
Security Fix
@@ -... @@ public function delete_all_generated_pages() { check_ajax_referer( 'lpagery_nonce', '_ajax_nonce' ); + if ( ! current_user_can( 'manage_options' ) ) { + wp_send_json_error( array( 'message' => 'Unauthorized' ), 403 ); + } + $posts = get_posts( array(
Exploit Outline
An attacker with Contributor-level access can perform administrative tasks by exploiting the 'lpagery_delete_all_generated' AJAX action. The attacker first logs into the WordPress admin panel and retrieves the required AJAX nonce from the localized 'lpagery_vars' or 'lpagery_obj' script object found on the Dashboard. They then submit a POST request to '/wp-admin/admin-ajax.php' containing the 'action=lpagery_delete_all_generated' and '_ajax_nonce=[NONCE]' parameters. Because the plugin only verifies the nonce and not user capabilities, the request succeeds and deletes all content marked with the plugin's internal meta keys.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.