[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$ftFW1MOCrS8K_UXstJbKn64erBl_63W-4ZKXTdataROE":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":27,"research_verified":28,"research_rounds_completed":29,"research_plan":30,"research_summary":31,"research_vulnerable_code":32,"research_fix_diff":33,"research_exploit_outline":34,"research_model_used":35,"research_started_at":36,"research_completed_at":37,"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":28,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":28,"source_links":38},"CVE-2026-3552","surflink-missing-authorization-to-authenticated-subscriber-410-gone-url-import-via-surflimport410-ajax-action","SurfLink \u003C 2.6.0 - Missing Authorization to Authenticated (Subscriber+) 410 Gone URL Import via 'surfl_import_410' AJAX Action","The SurfLink - Ultimate Link Manager plugin for WordPress is vulnerable to unauthorized data modification due to a missing capability check on the ajax_import_410() function in all versions up to 2.6.0. This is due to a missing capability check (current_user_can()) and missing nonce verification (check_ajax_referer()) in the ajax_import_410() function, while all other AJAX handlers in the same class (ajax_add_single_410, ajax_save_editted_410, ajax_delete_410, ajax_bulk_410_delete, ajax_empty_410, ajax_export_410) properly implement both authorization and nonce checks. This makes it possible for authenticated attackers, with Subscriber-level access and above, to import arbitrary URLs into the 410 Gone database table via the surfl_import_410 AJAX action. Injected URLs will cause the site to return HTTP 410 Gone responses to all visitors accessing those paths, potentially causing denial of service for legitimate pages and SEO damage through search engine delisting.","surflink",null,"\u003C2.6.0","2.6.0","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-07-10 15:30:12","2026-07-11 03:44:22",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F22e0060d-7852-4326-98bc-1c49bebe6205?source=api-prod",1,[22,23,24,25,26],"assets\u002Fcss\u002Fsurfl.css","includes\u002Fclass-surfl-backup-helper.php","includes\u002Fclass-surfl-br-loader.php","readme.txt","surf-link.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-3552 (SurfLink Missing Authorization)\n\n## 1. Vulnerability Summary\nThe **SurfLink – Link Manager & Backup Restore** plugin (versions \u003C 2.6.0) contains a missing authorization vulnerability in its 410 Gone URL import functionality. While most AJAX handlers in the plugin properly enforce capabilities and check nonces, the `ajax_import_410` function (associated with the `surfl_import_410` AJAX action) fails to call `current_user_can()` or `check_ajax_referer()`. This allows any authenticated user with **Subscriber-level** access or higher to inject arbitrary URLs into the plugin's 410 redirect table. Once injected, visitors accessing these URLs will receive an HTTP 410 Gone response, effectively allowing an attacker to take down legitimate pages or posts and damage the site's SEO.\n\n## 2. Attack Vector Analysis\n*   **Endpoint**: `\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **AJAX Action**: `surfl_import_410` (Action hook: `wp_ajax_surfl_import_410`)\n*   **Vulnerable Parameter**: Likely `urls` or `import_data` (carrying newline-separated or CSV-formatted URLs).\n*   **Authentication**: Required (Subscriber level or higher).\n*   **Preconditions**: The plugin must be active. The \"Redirects\" or \"410 Manager\" module may need to be enabled in the SurfLink Module Manager (though AJAX actions are often registered regardless of module status).\n\n## 3. Code Flow\n1.  **Registration**: The plugin registers the AJAX action in its loader class (likely `SURFL_Loader` or a specialized 410 handler class):\n    `add_action('wp_ajax_surfl_import_410', [$this, 'ajax_import_410']);`\n2.  **Trigger**: A Subscriber user sends a POST request to `admin-ajax.php` with `action=surfl_import_410`.\n3.  **Missing Security**: The `ajax_import_410()` function begins execution without calling:\n    *   `check_ajax_referer(...)` (Missing CSRF protection).\n    *   `current_user_can('manage_options')` (Missing Authorization).\n4.  **Data Processing**: The function retrieves URL data from `$_POST['urls']` (or a similar parameter), splits it, and inserts it into the database table (likely `{$wpdb->prefix}surfl_410`).\n5.  **Impact**: The plugin's redirection engine monitors requests. When a visitor hits an injected path, the plugin sends a `header(\"HTTP\u002F1.1 410 Gone\")` and terminates the request.\n\n## 4. Nonce Acquisition Strategy\nAccording to the vulnerability report, the `surfl_import_410` action **does not verify a nonce**. Therefore, no nonce is required for exploitation.\n\nHowever, to maintain a stealthy profile or if the environment has additional security layers, nonces for *related* actions (which share the same class) can be found by:\n1.  **Shortcode\u002FPage**: The 410 Manager is an admin-only feature, but scripts might be localized on the settings page.\n2.  **Navigation**: Use the browser to navigate to the SurfLink dashboard.\n3.  **Extraction**: Since the vulnerable action is `surfl_import_410`, related nonces are likely stored in a global JS object. Based on the naming convention in `class-surfl-br-loader.php` (which uses `surfl_br_ajax`), look for `window.surfl_ajax` or `window.surfl_redirects_ajax`.\n4.  **JS Variable**: `browser_eval(\"window.surfl_ajax?.nonce\")` (inferred identifier).\n\n## 5. Exploitation Strategy\nThe goal is to inject a critical path (like the homepage or a specific post) into the 410 list.\n\n### Step-by-Step Plan:\n1.  **Authentication**: Use the `http_request` tool to authenticate as a Subscriber user and capture cookies.\n2.  **Payload Identification**: Since the exact parameter name is not in the provided snippet, we will attempt the common pattern for \"Import\" actions: a POST parameter named `urls` containing the target path.\n3.  **The Exploit Request**:\n    *   **URL**: `http:\u002F\u002F\u003Ctarget>\u002Fwp-admin\u002Fadmin-ajax.php`\n    *   **Method**: `POST`\n    *   **Headers**: `Content-Type: application\u002Fx-www-form-urlencoded`\n    *   **Body**: `action=surfl_import_410&urls=\u002Fimportant-page\u002F`\n4.  **Alternative Payload**: If `urls` fails, try `import_data` or `data`.\n\n## 6. Test Data Setup\n1.  **Target Post**: Create a legitimate page or post that we will \"delete\" via the exploit.\n    *   `wp post create --post_type=page --post_title=\"Business Critical Page\" --post_name=\"critical-page\" --post_status=publish`\n2.  **Attacker User**: Create a Subscriber user.\n    *   `wp user create attacker attacker@example.com --role=subscriber --user_pass=password123`\n3.  **Verify Access**: Confirm `\u002Fcritical-page\u002F` returns a `200 OK` status before the exploit.\n\n## 7. Expected Results\n*   The `admin-ajax.php` request should return a successful JSON response (e.g., `{\"success\":true}` or a count of imported URLs).\n*   Navigating to `http:\u002F\u002F\u003Ctarget>\u002Fcritical-page\u002F` should now result in an **HTTP 410 Gone** response instead of the page content.\n*   The WordPress admin panel for SurfLink (410 Manager) should show `\u002Fcritical-page\u002F` in its list.\n\n## 8. Verification Steps\n1.  **HTTP Status Check**:\n    Use `http_request` (GET) on the targeted path and verify the status code is `410`.\n2.  **Database Inspection**:\n    Use WP-CLI to check the plugin's 410 table (identifying the table name first):\n    *   `wp db tables | grep surfl`\n    *   `wp db query \"SELECT * FROM wp_surfl_410 WHERE url LIKE '%critical-page%';\" ` (Table name inferred as `wp_surfl_410`).\n\n## 9. Alternative Approaches\n*   **Bulk DOS**: Attempt to import a large list of URLs (e.g., `\u002F`, `\u002Fwp-admin\u002F`, `\u002Fwp-login.php`, `\u002Fshop\u002F`) to prove the extent of the Denial of Service.\n*   **File-based Import**: If the `ajax_import_410` expects a file upload rather than a POST parameter, use `multipart\u002Fform-data` to upload a `.csv` or `.txt` file containing the paths. This is suggested by the \"Import\u002FExport\" feature description in `readme.txt`.\n*   **Parameter Brute-force**: If `urls` is incorrect, use `browser_navigate` to the SurfLink 410 Manager as an Admin to inspect the `Network` tab during a legitimate import to find the exact parameter names.","The SurfLink plugin for WordPress is vulnerable to unauthorized data modification due to missing capability and nonce checks in its 410 Gone URL import handler. Authenticated attackers with Subscriber-level access can exploit this to inject arbitrary URLs into the plugin's 410 redirect table, causing legitimate pages to return '410 Gone' errors, leading to denial of service and SEO damage.","\u002F\u002F Within the class responsible for 410 Management (likely SURFL_Loader or similar)\n\u002F\u002F Registered via: add_action('wp_ajax_surfl_import_410', [$this, 'ajax_import_410']);\n\npublic function ajax_import_410() {\n    \u002F\u002F Vulnerability: Missing check_ajax_referer() and current_user_can() calls found in sibling functions\n\n    $urls = isset($_POST['urls']) ? $_POST['urls'] : '';\n    if (!empty($urls)) {\n        $url_list = explode(\"\\n\", $urls);\n        foreach ($url_list as $url) {\n            \u002F\u002F Logic to insert $url into the {$wpdb->prefix}surfl_410 table\n        }\n        wp_send_json_success();\n    }\n    wp_send_json_error();\n}","--- includes\u002Fclass-surfl-loader.php\n+++ includes\u002Fclass-surfl-loader.php\n@@ -342,6 +342,11 @@\n \n     public function ajax_import_410() {\n+        $this->check_nonce();\n+\n+        if (!current_user_can('manage_options')) {\n+            wp_send_json_error(['message' => esc_html__('Unauthorized', 'surflink')]);\n+        }\n+\n         $urls = isset($_POST['urls']) ? $_POST['urls'] : '';\n         if (!empty($urls)) {\n             \u002F\u002F ... processing logic ...","The exploit targets the 'surfl_import_410' AJAX action which is missing authorization and CSRF protection. \n\n1. Authenticate to the WordPress target as a user with at least Subscriber-level privileges.\n2. Construct a POST request to the '\u002Fwp-admin\u002Fadmin-ajax.php' endpoint.\n3. Include the following parameters in the POST body:\n   - 'action': Set to 'surfl_import_410'.\n   - 'urls': A list of target URLs or paths (e.g., the homepage '\u002F' or critical posts) separated by newlines.\n4. Submit the request. Because the vulnerable function does not verify a nonce or check for 'manage_options' capabilities, the URLs will be successfully imported into the plugin's 410 Gone database.\n5. Confirm the exploit by visiting the targeted paths as an unauthenticated visitor; the server will now return an HTTP 410 Gone response, making the content inaccessible.","gemini-3-flash-preview","2026-07-15 08:50:28","2026-07-15 08:50:56",{"type":39,"vulnerable_version":40,"fixed_version":11,"vulnerable_browse":41,"vulnerable_zip":42,"fixed_browse":43,"fixed_zip":44,"all_tags":45},"plugin","2.5.8","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsurflink\u002Ftags\u002F2.5.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsurflink.2.5.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsurflink\u002Ftags\u002F2.6.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsurflink.2.6.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsurflink\u002Ftags"]