[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$f13ZIZ8u3W4xd-RIf72OPt8-nDPgDTeYmFlZmMlN14t4":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":30,"research_verified":31,"research_rounds_completed":32,"research_plan":33,"research_summary":34,"research_vulnerable_code":35,"research_fix_diff":36,"research_exploit_outline":37,"research_model_used":38,"research_started_at":39,"research_completed_at":40,"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":31,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":31,"source_links":41},"CVE-2026-48878","visual-link-preview-authenticated-subscriber-information-exposure","Visual Link Preview \u003C= 2.4.1 - Authenticated (Subscriber+) Information Exposure","The Visual Link Preview plugin for WordPress is vulnerable to Sensitive Information Exposure in all versions up to, and including, 2.4.1. This makes it possible for authenticated attackers, with Subscriber-level access and above, to extract sensitive user or configuration data.","visual-link-preview",null,"\u003C=2.4.1","2.4.2","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:L\u002FI:N\u002FA:N","Exposure of Sensitive Information to an Unauthorized Actor","2026-06-02 00:00:00","2026-06-11 14:06:03",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F6e3bf81a-cfc3-4203-9534-8a70f1fbc316?source=api-prod",10,[22,23,24,25,26,27,28,29],"assets\u002Fjs\u002Fblocks\u002Fvisual-link-preview\u002Fedit\u002Findex.js","assets\u002Fjs\u002Fblocks\u002Fvisual-link-preview\u002Findex.js","dist\u002Fblocks.js","includes\u002Fadmin\u002Fclass-vlp-assets.php","includes\u002Fclass-visual-link-preview.php","includes\u002Fpublic\u002Fclass-vlp-shortcode.php","includes\u002Fpublic\u002Fclass-vlp-template-manager.php","readme.txt","researched",false,3,"This research plan outlines the technical steps to exploit **CVE-2026-48878**, an Information Exposure vulnerability in the **Visual Link Preview** WordPress plugin (\u003C= 2.4.1).\n\n### 1. Vulnerability Summary\nThe `vlp_get_template` AJAX action in `VLP_Template_Manager` allows authenticated users to retrieve a preview of any post by providing its ID. The underlying logic in `VLP_Link` (the class processing the request) fails to verify if the current user has the necessary permissions to read the post being previewed. Consequently, any authenticated user with at least **Subscriber** level access can extract the title and content\u002Fsummary of private, password-protected, or draft posts. Additionally, the plugin localizes sensitive configuration data (such as API keys for external URL providers) into the `vlp_admin` and `vlp_blocks` JavaScript objects, making them visible to all logged-in users who can access the admin dashboard or block editor.\n\n### 2. Attack Vector Analysis\n*   **Vulnerable Endpoint:** `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Vulnerable AJAX Action:** `vlp_get_template`\n*   **Required Nonce:** `vlp` (Action: `vlp`)\n*   **Authentication:** Subscriber-level access or higher.\n*   **Preconditions:** The attacker must be logged in to obtain a valid nonce from the admin dashboard (e.g., the Profile page).\n\n### 3. Code Flow\n1.  **Registration:** In `includes\u002Fpublic\u002Fclass-vlp-template-manager.php`, the plugin registers the AJAX handler: \n    `add_action( 'wp_ajax_vlp_get_template', array( __CLASS__, 'ajax_get_template' ) );`.\n2.  **Entry Point:** When a request is sent to `vlp_get_template`, `VLP_Template_Manager::ajax_get_template()` is executed.\n3.  **Nonce Check:** The function verifies the `vlp` nonce: \n    `check_ajax_referer( 'vlp', 'security', false )`.\n4.  **Parsing:** It retrieves the `encoded` parameter from `$_POST`, which is a Base64-encoded JSON object.\n5.  **Object Creation:** `new VLP_Link( $encoded )` is instantiated. This class (logic inferred from usage) parses the JSON to set attributes like `type` and `post`.\n6.  **Information Retrieval:** It calls `$link->output()`, which fetches the post content corresponding to the `post` ID attribute without performing a `current_user_can('read_post', $post_id)` check.\n7.  **Exposure:** The rendered preview containing the private post's data is returned via `wp_send_json_success`.\n\n### 4. Nonce Acquisition Strategy\nSince the `vlp` nonce is used for admin-side functionality, it is localized via `wp_localize_script` in `VLP_Assets::enqueue()` (for the admin dashboard) and `VLP_Assets::enqueue_blocks()` (for Gutenberg).\n\n1.  **Login:** Authenticate as a Subscriber.\n2.  **Navigate:** Go to `\u002Fwp-admin\u002Fprofile.php` (accessible to all logged-in users).\n3.  **Extract:** Open the browser console and run:\n    ```javascript\n    console.log(window.vlp_admin.nonce);\n    ```\n    *Alternatively, search the page source for `vlp_admin` to find the JSON object containing the nonce.*\n\n### 5. Exploitation Strategy\nThe goal is to retrieve the content of a private post (e.g., Post ID 1337).\n\n1.  **Craft the Payload:** Create a JSON object specifying an internal post type and the target ID.\n    ```json\n    {\"type\": \"internal\", \"post\": 1337}\n    ```\n2.  **Encode the Payload:** Convert the JSON to Base64.\n    *   Example: `eyJ0eXBlIjogImludGVybmFsIiwgInBvc3QiOiAxMzM3fQ==`\n3.  **Send the HTTP Request:** Use the `http_request` tool to trigger the AJAX action.\n    *   **Method:** POST\n    *   **URL:** `http:\u002F\u002F[TARGET]\u002Fwp-admin\u002Fadmin-ajax.php`\n    *   **Headers:** `Content-Type: application\u002Fx-www-form-urlencoded`\n    *   **Body:** `action=vlp_get_template&security=[NONCE]&encoded=eyJ0eXBlIjogImludGVybmFsIiwgInBvc3QiOiAxMzM3fQ==`\n\n### 6. Test Data Setup\n1.  Create a private post with a unique title and sensitive content (e.g., \"Secret Project Alpha - Login: admin\u002Fpassword123\").\n2.  Identify the ID of this post (e.g., `1337`).\n3.  Create a user with the **Subscriber** role.\n4.  Ensure the Visual Link Preview plugin (version 2.4.1) is active.\n\n### 7. Expected Results\n*   The server returns a JSON response with `success: true`.\n*   The `data.template` field contains HTML markup.\n*   Within that HTML, the title and content of the private post (Post 1337) are visible (e.g., inside `\u003Ch3>` and `.summary` tags as defined in `VLP_Shortcode::register_blocks`).\n\n### 8. Verification Steps\n1.  **Confirm Privacy:** Using WP-CLI, verify the post is actually private:\n    `wp post get 1337 --field=post_status` (Expected: `private`).\n2.  **Confirm Exposure:** Check the `template` output from the HTTP response for the string \"Secret Project Alpha\".\n\n### 9. Alternative Approaches\n**Configuration Exposure (API Keys):**\nIf the plugin has a Microlink or LinkPreview API key configured, it may be exposed in the localized JS object.\n1.  Navigate to `\u002Fwp-admin\u002Fprofile.php`.\n2.  In the browser console, check:\n    ```javascript\n    console.log(window.vlp_admin.url_providers);\n    ```\n    Or check the source for the `vlp_blocks` object if the user has access to the post editor. Verify if any sensitive API keys are present in these objects.","The vlp_get_template AJAX action in the Visual Link Preview plugin fails to perform a capability check, allowing authenticated users with Subscriber-level access to retrieve previews of any post, including private or draft content, by providing its ID. Furthermore, sensitive configuration data such as API keys are localized into JavaScript objects accessible to all logged-in users, potentially exposing external service credentials.","\u002F\u002F includes\u002Fpublic\u002Fclass-vlp-template-manager.php line 152\npublic static function ajax_get_template() {\n\tif ( check_ajax_referer( 'vlp', 'security', false ) ) {\n\t\t$encoded = isset( $_POST['encoded'] ) ? sanitize_text_field( wp_unslash( $_POST['encoded'] ) ) : ''; \u002F\u002F Input var okay.\n\t\t$link = new VLP_Link( $encoded );\n\n\t\t$template = VLP_Template_Manager::get_template_by_slug( $link->template() );\n\n\t\t$output = '\u003Cstyle type=\"text\u002Fcss\">' . VLP_Template_Manager::get_template_css( $template ) . VLP_Template_Style::get_css() . '\u003C\u002Fstyle>';\n\t\t$output .= $link->output();\n\n\t\twp_send_json_success( array(\n\t\t\t'template' => $output,\n\t\t) );\n\t}\n\n\twp_die();\n}\n\n---\n\n\u002F\u002F includes\u002Fadmin\u002Fclass-vlp-assets.php line 83\nwp_localize_script( 'vlp-blocks', 'vlp_blocks', array(\n\t'ajax_url' => admin_url( 'admin-ajax.php' ),\n\t'nonce' => wp_create_nonce( 'vlp' ),\n\t'templates' => VLP_Template_Manager::get_templates(),\n\t'edit_link' => admin_url( 'post.php?action=edit&post='),\n\t'settings_link' => admin_url( 'options-general.php?page=bv_settings_vlp' ),\n\t'url_providers' => VLP_Url_Provider_Manager::get_available_providers(),\n));","--- includes\u002Fpublic\u002Fclass-vlp-template-manager.php\n+++ includes\u002Fpublic\u002Fclass-vlp-template-manager.php\n@@ -150,21 +150,29 @@\n \t * @since    1.0.0\n \t *\u002F\n \tpublic static function ajax_get_template() {\n-\t\tif ( check_ajax_referer( 'vlp', 'security', false ) ) {\n-\t\t\t$encoded = isset( $_POST['encoded'] ) ? sanitize_text_field( wp_unslash( $_POST['encoded'] ) ) : ''; \u002F\u002F Input var okay.\n-\t\t\t$link = new VLP_Link( $encoded );\n-\n-\t\t\t$template = VLP_Template_Manager::get_template_by_slug( $link->template() );\n-\n-\t\t\t$output = '\u003Cstyle type=\"text\u002Fcss\">' . VLP_Template_Manager::get_template_css( $template ) . VLP_Template_Style::get_css() . '\u003C\u002Fstyle>';\n-\t\t\t$output .= $link->output();\n-\n-\t\t\twp_send_json_success( array(\n-\t\t\t\t'template' => $output,\n-\t\t\t) );\n+\t\tif ( ! check_ajax_referer( 'vlp', 'security', false ) ) {\n+\t\t\twp_send_json_error( array(\n+\t\t\t\t'message' => __( 'Invalid security token.', 'visual-link-preview' ),\n+\t\t\t), 403 );\n \t\t}\n \n-\t\twp_die();\n+\t\tif ( ! current_user_can( 'edit_posts' ) ) {\n+\t\t\twp_send_json_error( array(\n+\t\t\t\t'message' => __( 'You do not have permission to preview templates.', 'visual-link-preview' ),\n+\t\t\t), 403 );\n+\t\t}\n+\n+\t\t$encoded = isset( $_POST['encoded'] ) ? sanitize_text_field( wp_unslash( $_POST['encoded'] ) ) : ''; \u002F\u002F Input var okay.\n+\t\t$link = new VLP_Link( $encoded );\n+\n+\t\t$template = VLP_Template_Manager::get_template_by_slug( $link->template() );\n+\n+\t\t$output = '\u003Cstyle type=\"text\u002Fcss\">' . VLP_Template_Manager::get_template_css( $template ) . VLP_Template_Style::get_css() . '\u003C\u002Fstyle>';\n+\t\t$output .= $link->output();\n+\n+\t\twp_send_json_success( array(\n+\t\t\t'template' => $output,\n+\t\t) );\n \t}","1. Authenticate to the WordPress site as a user with at least Subscriber-level privileges.\n2. Retrieve the required 'vlp' AJAX nonce by inspecting the page source of an administrative page (like \u002Fwp-admin\u002Fprofile.php) or by checking the 'vlp_admin.nonce' value in the browser console.\n3. Target a private or draft post by its numeric ID.\n4. Prepare a JSON object: {\"type\": \"internal\", \"post\": [TARGET_ID]}.\n5. Base64-encode this JSON string.\n6. Execute an AJAX request to \u002Fwp-admin\u002Fadmin-ajax.php with the POST parameters: 'action' set to 'vlp_get_template', 'security' set to the retrieved nonce, and 'encoded' set to the Base64-encoded JSON.\n7. The response will contain the HTML-rendered preview of the private post, exposing its title and summary.","gemini-3-flash-preview","2026-06-26 06:08:16","2026-06-26 06:09:39",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","2.4.1","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fvisual-link-preview\u002Ftags\u002F2.4.1","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fvisual-link-preview.2.4.1.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fvisual-link-preview\u002Ftags\u002F2.4.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fvisual-link-preview.2.4.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fvisual-link-preview\u002Ftags"]