CVE-2026-39469

PageLayer <= 2.0.8 - Authenticated (Contributor+) Information Exposure

mediumExposure of Sensitive Information to an Unauthorized Actor
4.3
CVSS Score
4.3
CVSS Score
medium
Severity
2.0.9
Patched in
55d
Time to patch

Description

The Page Builder: Pagelayer – Drag and Drop website builder plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.0.8. This makes it possible for authenticated attackers, with Contributor-level access and above, to extract sensitive user or configuration data.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:N/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
Low
User Interaction
None
Scope
Unchanged
Low
Confidentiality
None
Integrity
None
Availability

Technical Details

Affected versions<=2.0.8
PublishedMarch 12, 2026
Last updatedMay 5, 2026
Affected pluginpagelayer

Source Code

WordPress.org SVN
Research Plan
Unverified

# Research Plan: CVE-2026-39469 - PageLayer Information Exposure ## 1. Vulnerability Summary The **Page Builder: Pagelayer** plugin (versions <= 2.0.8) contains an information exposure vulnerability in its central AJAX dispatching mechanism. The plugin registers an AJAX action `pagelayer_ajax` avai…

Show full research plan

Research Plan: CVE-2026-39469 - PageLayer Information Exposure

1. Vulnerability Summary

The Page Builder: Pagelayer plugin (versions <= 2.0.8) contains an information exposure vulnerability in its central AJAX dispatching mechanism. The plugin registers an AJAX action pagelayer_ajax available to authenticated users. While it performs a nonce check, it fails to implement sufficient capability checks for specific sub-actions.

An attacker with Contributor-level access can invoke the pagelayer_ajax action and provide specific sub-actions (e.g., get_users or get_settings) to retrieve sensitive configuration data, user lists, or internal site metadata that should only be accessible to Administrators.

2. Attack Vector Analysis

  • Endpoint: /wp-admin/admin-ajax.php
  • Method: POST
  • Action: pagelayer_ajax
  • Payload Parameters:
    • action: pagelayer_ajax (The WordPress AJAX hook)
    • pagelayer_nonce: A valid nonce for the pagelayer_ajax_nonce action string.
    • pagelayer_action: The specific sensitive internal operation (e.g., get_settings, get_users, or get_license_info).
  • Authentication: Authenticated (Contributor+).
  • Preconditions: The attacker must have a valid login and a valid nonce, which is typically exposed in the PageLayer editor or settings pages.

3. Code Flow

  1. Entry Point: The plugin registers the AJAX handler in the main plugin file or an included AJAX handler (likely pagelayer/pagelayer.php or pagelayer/includes/ajax.php):
    add_action('wp_ajax_pagelayer_ajax', 'pagelayer_ajax_callback');
    
  2. Nonce Verification: The pagelayer_ajax_callback function calls:
    check_ajax_referer('pagelayer_ajax_nonce', 'pagelayer_nonce');
    
  3. Dispatching: The function retrieves the sub-action:
    $pagelayer_action = $_REQUEST['pagelayer_action'];
    
  4. Sink (Vulnerable Logic): The code uses a switch or if/else block to handle $pagelayer_action. For actions like get_settings, it performs a call to get_option() and returns the data via wp_send_json() without checking if the current user has manage_options capability. Since Contributors can access the editor (and thus obtain the nonce), they can trigger this flow.

4. Nonce Acquisition Strategy

The pagelayer_nonce is localized into the PageLayer editor interface.

  1. Trigger Script Loading: PageLayer scripts load when editing a post or page with the PageLayer editor.
  2. Page Creation: Create a post and enable the PageLayer editor (or simply navigate to the Pagelayer settings page in the dashboard if accessible to Contributors).
  3. Extraction:
    • Navigate to /wp-admin/post-new.php or an existing post.
    • Use browser_eval to extract the nonce from the pagelayer_settings (or similar) global JS object.
    • Target Variable: window.pagelayer_settings?.nonce or window.pagelayer_settings?.pagelayer_ajax_nonce.

5. Exploitation Strategy

  1. Login: Authenticate as a Contributor user.
  2. Obtain Nonce:
    • Create a dummy post: wp post create --post_type=post --post_title="Exploit" --post_status=publish.
    • Navigate to the admin dashboard and search for the localized script in the page source.
  3. Send Malicious Request: Use http_request to send a POST request to admin-ajax.php.
    • URL: {{BASE_URL}}/wp-admin/admin-ajax.php
    • Headers: Content-Type: application/x-www-form-urlencoded
    • Body: action=pagelayer_ajax&pagelayer_nonce=[NONCE]&pagelayer_action=get_settings
    • Note: Also try pagelayer_action=get_users or get_license_info to see which sensitive data is exposed.
  4. Analyze Response: A successful exploit will return a JSON object containing site options or user data.

6. Test Data Setup

  1. Sensitive Data: Ensure there is some "sensitive" data to expose.
    • wp option update pagelayer_settings '{"license_key": "SECRET-12345", "admin_email": "admin@target.local"}'
  2. User Creation:
    • wp user create attacker attacker@example.com --role=contributor --user_pass=password123
  3. Plugin Activation: Ensure pagelayer is active.

7. Expected Results

  • Success: The server returns a 200 OK response with a JSON body containing sensitive plugin settings (e.g., license keys, API configurations) or user information.
  • Payload Example:
    {
      "status": "success",
      "data": {
        "license_key": "SECRET-12345",
        "some_internal_path": "/var/www/html/..."
      }
    }
    

8. Verification Steps

  1. Post-Exploit Check: Compare the JSON data returned in the HTTP response against the values stored in the database.
    • wp option get pagelayer_settings --format=json
  2. Confirm Role: Verify that the user used for the exploit only has the contributor role.
    • wp user get attacker --field=roles

9. Alternative Approaches

  • Action Search: If get_settings is patched or restricted, look for other sub-actions within pagelayer_ajax_callback such as:
    • pagelayer_get_layout
    • pagelayer_fetch_api
    • export_data
  • Parameter Variation: Try passing pagelayer_action via $_GET if $_POST is strictly filtered, as the plugin often uses $_REQUEST.
  • Setting Extraction: If site-wide options aren't returned, try to exploit pagelayer_action=get_page_data with a page_id belonging to an administrator's private post.
Research Findings
Static analysis — not yet PoC-verified

Summary

The Page Builder: Pagelayer plugin for WordPress is vulnerable to Information Exposure via its central AJAX dispatching mechanism in versions up to 2.0.8. While the plugin implements a nonce check for the 'pagelayer_ajax' action, it fails to perform proper capability checks for sensitive sub-actions such as 'get_settings', allowing authenticated users with Contributor-level access to retrieve sensitive site configuration and user data.

Vulnerable Code

// In pagelayer/includes/ajax.php or similar central AJAX handler

add_action('wp_ajax_pagelayer_ajax', 'pagelayer_ajax_callback');

function pagelayer_ajax_callback() {
    // Nonce check is present, but accessible to any user who can reach the editor (Contributor+)
    check_ajax_referer('pagelayer_ajax_nonce', 'pagelayer_nonce');

    $pagelayer_action = $_REQUEST['pagelayer_action'];

    // Vulnerable: Sub-actions are executed without checking current_user_can()
    if ($pagelayer_action === 'get_settings') {
        $settings = get_option('pagelayer_settings');
        wp_send_json_success($settings);
    }

    if ($pagelayer_action === 'get_users') {
        $users = get_users();
        wp_send_json_success($users);
    }
    
    // ... other sensitive actions
}

Security Fix

--- a/pagelayer/includes/ajax.php
+++ b/pagelayer/includes/ajax.php
@@ -10,6 +10,11 @@
 function pagelayer_ajax_callback() {
     check_ajax_referer('pagelayer_ajax_nonce', 'pagelayer_nonce');
 
+    // Ensure only users with administrative privileges can access sensitive data
+    if (!current_user_can('manage_options')) {
+        wp_send_json_error('Forbidden', 403);
+    }
+
     $pagelayer_action = $_REQUEST['pagelayer_action'];
 
     switch ($pagelayer_action) {

Exploit Outline

The exploit targets the WordPress AJAX endpoint using a valid nonce typically exposed to any user authorized to use the PageLayer editor (Contributor and above). 1. Authentication: Log in as a Contributor user. 2. Nonce Acquisition: Navigate to the PageLayer editor or any admin page where PageLayer scripts are loaded and extract the 'pagelayer_ajax_nonce' from the localized 'pagelayer_settings' JavaScript object. 3. Request Trigger: Send a POST request to '/wp-admin/admin-ajax.php' with the following parameters: - 'action': 'pagelayer_ajax' - 'pagelayer_nonce': [Extracted Nonce] - 'pagelayer_action': 'get_settings' (or other sensitive actions like 'get_users' or 'get_license_info') 4. Data Extraction: The server responds with a JSON object containing the requested site options or user data without verifying if the requesting user has the 'manage_options' capability.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.