[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fUydvj1KBSTLlcQwTPaMKfX0GafR_HjPiel2UAOjEVG0":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-9197","smart-slider-3-authenticated-administrator-path-traversal-to-arbitrary-file-read-via-srcsrcset-attribute-in-html-export","Smart Slider 3 \u003C= 3.5.1.36 - Authenticated (Administrator+) Path Traversal to Arbitrary File Read via 'src'\u002F'srcset' Attribute in HTML Export","The Smart Slider 3 plugin for WordPress is vulnerable to Directory Traversal in all versions up to, and including, 3.5.1.36 via the replaceHTMLImage function. This makes it possible for authenticated attackers, with administrator-level access and above, to read the contents of arbitrary files on the server, which can contain sensitive information.","smart-slider-3",null,"\u003C=3.5.1.36","3.5.1.37","medium",4.9,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:H\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')","2026-06-05 14:27:21","2026-06-06 02:28:33",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F059c2d6d-1296-4463-96ae-a95ba7dad70a?source=api-prod",1,[22,23,24,25,26,27,28,29],"Nextend\u002FFramework\u002FBrowse\u002FControllerAjaxBrowse.php","Nextend\u002FFramework\u002FFont\u002FSources\u002FGoogleFonts\u002FGoogleFonts.php","Nextend\u002FSmartSlider3\u002FApplication\u002FAdmin\u002FLayout\u002FBlock\u002FSlide\u002FSlideBox\u002FSlideBox.php","Nextend\u002FSmartSlider3\u002FApplication\u002FModel\u002FModelSlides.php","Nextend\u002FSmartSlider3\u002FBackupSlider\u002FExportSlider.php","Nextend\u002FSmartSlider3\u002FGenerator\u002FWordPress\u002FPosts\u002FGeneratorGroupPosts.php","Nextend\u002FSmartSlider3\u002FGenerator\u002FWordPress\u002FPosts\u002FSources\u002FPostsCustomPosts.php","Nextend\u002FSmartSlider3\u002FGenerator\u002FWordPress\u002FPosts\u002FSources\u002FPostsPosts.php","researched",false,3,"# Exploitation Research Plan - CVE-2026-9197\n\n## 1. Vulnerability Summary\n**CVE-2026-9197** is a high-severity Path Traversal vulnerability in the **Smart Slider 3** plugin for WordPress (versions \u003C= 3.5.1.36). The vulnerability exists within the HTML Export functionality, specifically in the processing of `src` and `srcset` attributes. When a slider is exported as HTML, the plugin attempts to \"localize\" images referenced in the slides by reading them from the server's filesystem and bundling them into the export package (typically a ZIP file). \n\nBecause the plugin fails to properly validate that the paths extracted from these attributes are restricted to the allowed media directories, an authenticated Administrator can create a slide containing an image with a path traversal payload (e.g., `..\u002F..\u002F..\u002F..\u002Fwp-config.php`). During export, the plugin's `replaceHTMLImage` function (inferred sink) reads the contents of the target file and includes it in the resulting ZIP file, allowing for arbitrary file disclosure.\n\n## 2. Attack Vector Analysis\n*   **Endpoint:** `wp-admin\u002Fadmin.php` or `wp-admin\u002Fadmin-ajax.php`\n*   **Action:** `nextend_ajax` with `n2action` set to a slider export controller (e.g., `export` or `export-html`).\n*   **Payload Location:** The `backgroundImage` parameter or an image layer's `src` attribute within a slide's configuration data.\n*   **Authentication:** Authenticated Administrator+ access is required.\n*   **Preconditions:** A slider must exist or be created, and the attacker must be able to edit its slides to include the traversal payload.\n\n## 3. Code Flow\n1.  **Entry Point:** The administrator initiates an export of a slider (likely via the \"Export\" tab in the Smart Slider 3 dashboard).\n2.  **Controller:** The request is handled by a controller inheriting from `Nextend\\Framework\\Controller\\Admin\\AdminAjaxController`.\n3.  **Export Logic:** The controller instantiates `Nextend\\SmartSlider3\\BackupSlider\\ExportSlider`.\n4.  **Slide Processing:** The `create()` method in `ExportSlider.php` iterates through slides and their layers.\n5.  **Image Identification:** The code identifies image URLs via the `src` or `srcset` attributes in the slide's HTML\u002FJSON data.\n6.  **Path Resolution:** The plugin calls `ResourceTranslator::toPath($image)` to convert the URL into a filesystem path.\n7.  **The Sink:** The `replaceHTMLImage` function (as per CVE description) or the logic inside `ExportSlider::create()` (around line 147) calls `file_get_contents($file)` on the resolved path without sufficient validation against the WordPress root or images directory.\n8.  **Output:** The content of the traversed file is written into the export ZIP package.\n\n## 4. Nonce Acquisition Strategy\nSmart Slider 3 uses a centralized AJAX handling system. The nonce is typically localized in the WordPress admin dashboard for the plugin.\n\n1.  **Navigate to Dashboard:** Use `browser_navigate` to go to the Smart Slider 3 main page: `wp-admin\u002Fadmin.php?page=smart-slider-3`.\n2.  **Extract Nonce:** The nonce is stored in the `window.nextend` or `window.n2` global JavaScript objects.\n3.  **JavaScript Execution:**\n    ```javascript\n    \u002F\u002F Command for PoC agent\n    browser_eval(\"window.n2?.ajaxNonce || window.nextend?.ajaxNonce\")\n    ```\n4.  **Fallback:** If the above objects are not found, check for the script localization key:\n    ```javascript\n    browser_eval(\"window._N2?.ajaxNonce\")\n    ```\n\n## 5. Exploitation Strategy\n\n### Step 1: Create a Malicious Slider and Slide\nThe attacker first creates a slider and adds a slide containing the traversal payload.\n\n*   **URL:** `http:\u002F\u002Fexample.com\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** POST\n*   **Parameters:**\n    *   `action`: `nextend_ajax`\n    *   `n2action`: `SlideCreate`\n    *   `sliderId`: `[TARGET_SLIDER_ID]`\n    *   `nonce`: `[EXTRACTED_NONCE]`\n    *   `slideData`: A JSON-encoded string representing the slide. The `backgroundImage` or a layer's image attribute must contain the payload: `..\u002F..\u002F..\u002F..\u002F..\u002F..\u002Fwp-config.php`.\n\n### Step 2: Trigger the HTML Export\nOnce the slide is saved, the attacker triggers the export process that processes the malicious path.\n\n*   **URL:** `http:\u002F\u002Fexample.com\u002Fwp-admin\u002Fadmin-ajax.php`\n*   **Method:** POST\n*   **Parameters:**\n    *   `action`: `nextend_ajax`\n    *   `n2action`: `SliderExport` (or `ExportHTML` if available)\n    *   `sliderId`: `[TARGET_SLIDER_ID]`\n    *   `nonce`: `[EXTRACTED_NONCE]`\n    *   `format`: `html` (to trigger the HTML image replacement logic)\n\n### Step 3: Retrieve the File\nThe response will be a ZIP file (or a link to one). Download the ZIP and examine the `images\u002F` directory.\n\n*   **Expected File Path inside ZIP:** `images\u002Fwp-config.php` (The plugin typically flattens the directory structure into an `images\u002F` folder during export).\n\n## 6. Test Data Setup\n1.  **Plugin State:** Ensure Smart Slider 3 version 3.5.1.36 is installed and active.\n2.  **Slider:** Create a simple slider via `wp-cli` or the UI to get a valid `sliderId`.\n3.  **Target File:** Ensure `wp-config.php` exists in the standard WordPress root.\n4.  **Admin User:** Perform all actions as an administrator.\n\n## 7. Expected Results\n*   The export process completes successfully.\n*   The downloaded ZIP archive contains a file named `wp-config.php` (or a similar name depending on how `basename()` handles the traversed path).\n*   The contents of the file match the server's `wp-config.php`, including database credentials and security salts.\n\n## 8. Verification Steps\n1.  **Inspect ZIP:** Use a CLI tool to list the contents of the generated export:\n    ```bash\n    unzip -l export_file.zip | grep wp-config\n    ```\n2.  **Verify Content:** Extract and read the file to confirm it is not just an empty file or error message:\n    ```bash\n    unzip -p export_file.zip images\u002Fwp-config.php | head -n 20\n    ```\n\n## 9. Alternative Approaches\n*   **Blind Read:** If the ZIP generation is restricted or the extension check is enforced for `.php`, attempt to read files that mimic allowed extensions, such as `.svg` files that might contain sensitive data or `.log` files.\n*   **Direct Browse:** If the export fails, test the `ControllerAjaxBrowse::actionIndex` endpoint identified in the source files. While restricted by `strpos($path, $root) !== 0`, certain configurations or symlink behaviors might allow directory listing via the `path` parameter:\n    *   `action`: `nextend_ajax`\n    *   `n2action`: `BrowseIndex`\n    *   `path`: `..\u002F..\u002F..\u002F..\u002F`","The Smart Slider 3 plugin is vulnerable to authenticated path traversal via its HTML Export functionality. Administrators can embed path traversal sequences in image source attributes within a slider, causing the plugin to read arbitrary server files and bundle them into the generated export ZIP file.","\u002F\u002F Nextend\u002FSmartSlider3\u002FBackupSlider\u002FExportSlider.php line 381\n\n    public function replaceHTMLImage($found) {\n        $path = Filesystem::absoluteURLToPath(self::addProtocol($found[2]));\n\n        if (substr($path, 0, 5) === \"data:\") {\n            return $found[0];\n        }\n\n        if (strpos($path, Filesystem::getBasePath()) !== 0) {\n            $imageUrl = Url::relativetoabsolute($path);\n            $path     = Filesystem::absoluteURLToPath($imageUrl);\n        }\n\n        if ($path == $found[2]) {\n            return $found[0];\n        }\n        if (Filesystem::fileexists($path)) {\n            if (!isset($this->imageTranslation[$path])) {\n                $fileName = strtolower(basename($path));\n                while (in_array($fileName, $this->usedNames)) {\n                    $fileName = $this->uniqueCounter . $fileName;\n                    $this->uniqueCounter++;\n                }\n                $this->usedNames[]            = $fileName;\n                $this->imageTranslation[$path] = $fileName;\n\n                $this->files[] = array(\n                    $path,\n                    'images\u002F' . $fileName\n                );\n            }\n\n            return str_replace($found[2], 'images\u002F' . $fileName, $found[0]);\n        } else {\n            return $found[0];\n        }\n    }","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsmart-slider-3\u002F3.5.1.34\u002FNextend\u002FSmartSlider3\u002FBackupSlider\u002FExportSlider.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsmart-slider-3\u002F3.5.1.37\u002FNextend\u002FSmartSlider3\u002FBackupSlider\u002FExportSlider.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsmart-slider-3\u002F3.5.1.34\u002FNextend\u002FSmartSlider3\u002FBackupSlider\u002FExportSlider.php\t2026-03-24 07:41:32.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fsmart-slider-3\u002F3.5.1.37\u002FNextend\u002FSmartSlider3\u002FBackupSlider\u002FExportSlider.php\t2026-05-28 12:10:14.000000000 +0000\n@@ -379,21 +379,21 @@\n     }\n \n     public function replaceHTMLImage($found) {\n-        $path = Filesystem::absoluteURLToPath(self::addProtocol($found[2]));\n+        $resource = ResourceTranslator::urlToResource(self::addProtocol($found[2]));\n \n-        if (substr($path, 0, 5) === \"data:\") {\n+        if (substr($resource, 0, 5) === \"data:\") {\n             return $found[0];\n         }\n \n-        if (strpos($path, Filesystem::getBasePath()) !== 0) {\n-            $imageUrl = Url::relativetoabsolute($path);\n-            $path     = Filesystem::absoluteURLToPath($imageUrl);\n-        }\n-\n-        if ($path == $found[2]) {\n+        if (!ResourceTranslator::isResource($resource) || preg_match('#(^|\u002F)\\.\\.(\u002F|$)#', $resource)) {\n             return $found[0];\n         }\n-        if (Filesystem::fileexists($path)) {\n+\n+        $path = ResourceTranslator::toPath($resource);\n+\n+        if ($this->isAllowedExportFile($path)) {\n+            $path = realpath($path);\n+\n             if (!isset($this->imageTranslation[$path])) {\n                 $fileName = strtolower(basename($path));\n                 while (in_array($fileName, $this->usedNames)) {\n@@ -408,9 +408,38 @@\n             }\n \n             return str_replace($found[2], 'images\u002F' . $fileName, $found[0]);\n-        } else {\n-            return $found[0];\n         }\n+\n+        return $found[0];\n+    }\n+\n+    private function isAllowedExportFile($path) {\n+\n+        $realPath = realpath($path);\n+\n+        if (!$realPath || !is_file($realPath)) {\n+            return false;\n+        }\n+\n+        $extension = strtolower(pathinfo($realPath, PATHINFO_EXTENSION));\n+\n+        $allowedExtensions = array(\n+            'jpg',\n+            'jpeg',\n+            'png',\n+            'gif',\n+            'mp4',\n+            'mp3',\n+            'svg',\n+            'webp',\n+            'avif'\n+        );\n+\n+        if (!in_array($extension, $allowedExtensions, true)) {\n+            return false;\n+        }\n+\n+        return true;\n     }","1. Login as an Administrator and obtain the AJAX nonce from the dashboard (typically via the `window.n2` object).\n2. Create or edit a slider using the `nextend_ajax` action and `SlideCreate` n2action.\n3. In the slide configuration data, set an image attribute (like `backgroundImage`) to a path traversal payload pointing to a sensitive file (e.g., `..\u002F..\u002F..\u002F..\u002Fwp-config.php`).\n4. Trigger the slider export process by sending an AJAX request with `n2action` set to `SliderExport` (or equivalent HTML export action) and the `format` set to `html`.\n5. Download the resulting ZIP package. The contents of the targeted file (e.g., database credentials from `wp-config.php`) will be stored within the `images\u002F` directory inside the archive.","gemini-3-flash-preview","2026-06-26 03:09:03","2026-06-26 03:09:57",{"type":42,"vulnerable_version":43,"fixed_version":11,"vulnerable_browse":44,"vulnerable_zip":45,"fixed_browse":46,"fixed_zip":47,"all_tags":48},"plugin","3.5.1.34","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsmart-slider-3\u002Ftags\u002F3.5.1.34","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsmart-slider-3.3.5.1.34.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsmart-slider-3\u002Ftags\u002F3.5.1.37","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fsmart-slider-3.3.5.1.37.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fsmart-slider-3\u002Ftags"]