[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fGDoBjuhCFs2UT_IO4OCJu_JcnEqVqeyM1ZzcJeWakXc":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":16,"references":17,"days_to_patch":19,"patch_diff_files":20,"patch_trac_url":9,"research_status":25,"research_verified":26,"research_rounds_completed":27,"research_plan":28,"research_summary":29,"research_vulnerable_code":30,"research_fix_diff":31,"research_exploit_outline":32,"research_model_used":33,"research_started_at":34,"research_completed_at":35,"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":26,"poc_model_used":9,"poc_verification_depth":9,"source_links":36},"CVE-2026-3369","better-find-and-replace-ai-powered-suggestions-authenticated-author-stored-cross-site-scripting-via-uploaded-image-title","Better Find and Replace – AI-Powered Suggestions \u003C= 1.7.9 - Authenticated (Author+) Stored Cross-Site Scripting via Uploaded Image Title","The Better Find and Replace – AI-Powered Suggestions plugin for WordPress is vulnerable to Stored Cross-Site Scripting via uploaded image title in versions up to, and including, 1.7.9 due to insufficient input sanitization and output escaping. This makes it possible for authenticated attackers, with author-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.","real-time-auto-find-and-replace",null,"\u003C=1.7.9","1.8.0","medium",5.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:R\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-04-15 22:04:39",[18],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F497c2f5f-ed7d-486e-baf2-aefbe3dc412f?source=api-prod",0,[21,22,23,24],"assets\u002Fjs\u002Frtafar.media.replacer.min.js","readme.txt","real-time-auto-find-and-replace.php","vendor\u002Fcomposer\u002Finstalled.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-3369\n\n## 1. Vulnerability Summary\nThe **Better Find and Replace – AI-Powered Suggestions** plugin (up to 1.7.9) is vulnerable to **Stored Cross-Site Scripting (XSS)**. The vulnerability exists in the plugin's media replacement interface, specifically within the `assets\u002Fjs\u002Frtafar.media.replacer.min.js` file. The plugin fetches attachment data (including titles) and dynamically constructs HTML strings to display search results and previews. Because it fails to sanitize or escape the `title` attribute of images before injecting them into the DOM using jQuery's `.html()` method, an authenticated user with Author-level permissions can upload an image with a malicious title to execute arbitrary JavaScript in the context of any user (typically an administrator) who uses the plugin's media management tools.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `wp-admin\u002Fadmin-ajax.php` (for searching) and `wp-admin\u002Fadmin.php?page=rtafar-media-replacer` (the UI where XSS triggers).\n- **Vulnerable Parameter:** The `post_title` (Title) of an uploaded attachment.\n- **Authentication Level:** **Author** or higher. Authors have the `upload_files` and `edit_posts` capabilities required to upload media and modify its metadata.\n- **Preconditions:** The attacker must be able to upload an image and modify its title. The victim (Admin) must navigate to the plugin's \"Media Replacer\" page and either perform a search or initiate a replacement that renders the malicious image's title.\n\n## 3. Code Flow\n1. **Data Source:** The attacker uploads an image. WordPress stores the title in the `wp_posts` table (column `post_title`).\n2. **Data Retrieval:** In the admin interface, `assets\u002Fjs\u002Frtafar.media.replacer.min.js` uses the `query-attachments` AJAX action to find images.\n3. **Construction (Sink 1 - Search Results):**\n   - Inside `setupSearchInput`, the plugin receives a JSON array of attachments.\n   - It iterates through the results and builds an HTML string:\n     ```javascript\n     \u002F\u002F Truncated from assets\u002Fjs\u002Frtafar.media.replacer.min.js\n     return '\u003Cdiv class=\"image-item\">\\n \u003Cimg ... alt=\"'.concat(e.title, '\" ...>')\n     ```\n   - It then calls `jQuery(\".image-container\").html(t)`, where `t` is the unsanitized string.\n4. **Construction (Sink 2 - Preview Modal):**\n   - In `setupReplaceButton`, the plugin calls `wp.media.attachment(id).fetch()`.\n   - It uses the `imagePreview` function:\n     ```javascript\n     imagePreview: function(e, t, a) {\n         return '\u003Cimg ... alt=\"'.concat(a, '\"  \u002F>') \u002F\u002F 'a' is the title\n     }\n     ```\n   - It then calls `jQuery(\".old-media-preview-wrapper\").html(...)` with the result.\n\n## 4. Nonce Acquisition Strategy\nThe `query-attachments` action is a WordPress core AJAX handler. While it usually requires a nonce, the plugin's custom media page enqueues the standard WordPress media library, which provides these nonces.\n\n1. **Identify the Page:** The media replacer tool is located at `wp-admin\u002Fadmin.php?page=rtafar-media-replacer` (inferred from JS naming).\n2. **Accessing the Page:** The PoC agent should navigate to this page using `browser_navigate`.\n3. **Extracting the Nonce:** If the `query-attachments` call requires a nonce, it is typically stored in the `wp.media` configuration.\n   - **JavaScript Check:** `browser_eval(\"wp.media.view.settings.post.nonce\")`.\n   - **Alternative:** Check for a localized object like `rtafar_media_replacer_vars`.\n\n## 5. Exploitation Strategy\n1. **Upload Malicious Media:**\n   - Authenticate as an **Author**.\n   - Upload a legitimate image file (e.g., `image.jpg`) using `wp-admin\u002Fasync-upload.php`.\n   - Capture the `attachment_id` from the response.\n2. **Inject XSS Payload into Title:**\n   - Use a `POST` request to `wp-admin\u002Fpost.php` to update the attachment's metadata.\n   - **Payload:** `poc\" onerror=\"alert(document.domain)\" x=\"`\n   - This payload breaks out of the `alt=\"...\"` attribute.\n3. **Trigger XSS (Victim Perspective):**\n   - Authenticate as an **Administrator**.\n   - Navigate to `wp-admin\u002Fadmin.php?page=rtafar-media-replacer`.\n   - Locate the search input (class `.input-media-replace-query`).\n   - Type a search string (e.g., \"poc\") that matches the malicious image's title.\n   - The plugin will fetch the attachment and call `.html()`, triggering the `onerror` event.\n\n## 6. Test Data Setup\n- **User:** Create a user with the `author` role.\n- **Image:** A standard JPG file named `test.jpg`.\n- **Plugin Page:** Ensure the plugin \"Better Find and Replace\" is active.\n\n## 7. Expected Results\n- When the Administrator searches for the image in the \"Media Replacer\" tool, the `alt` attribute of the rendered `\u003Cimg>` tag will be: `alt=\"poc\" onerror=\"alert(document.domain)\" x=\"\"`.\n- The browser will attempt to load the image, and upon the (inevitable) completion or error, the `onerror` handler will fire, executing `alert(document.domain)`.\n\n## 8. Verification Steps\n1. **Database Check:**\n   - `wp db query \"SELECT post_title FROM wp_posts WHERE post_type='attachment' AND post_title LIKE '%onerror%'\"`.\n2. **AJAX Response Check:**\n   - Intercept the `query-attachments` response in the browser or via `http_request` and verify the `title` field contains the raw payload: `\"title\":\"poc\\\" onerror=\\\"alert(document.domain)\\\" x=\\\"\"`.\n3. **DOM Inspection:**\n   - Use `browser_eval(\"document.querySelector('.image-container img')?.getAttribute('onerror')\")` to confirm the attribute was successfully injected into the DOM.\n\n## 9. Alternative Approaches\nIf the search results gallery doesn't trigger immediately:\n- **Preview Trigger:** Click the \"Replace\" button (class `.btn-img-replace`) on any image in the search results. This triggers the `imagePreview` logic and `setupReplaceButton` logic, which also uses the unsanitized title in a `.html()` sink.\n- **Video Vector:** The code also handles video types. Try uploading a video and setting the title, as the `setupSearchInput` function handles videos in a similar (though slightly different) unsanitized concatenation path.","The Better Find and Replace – AI-Powered Suggestions plugin for WordPress is vulnerable to Stored Cross-Site Scripting (XSS) in versions up to 1.7.9. This occurs because the plugin's Media Replacer tool fails to sanitize or escape image titles before injecting them into the administrative interface using jQuery's .html() method, allowing Author-level users to execute arbitrary JavaScript in an administrator's session.","\u002F\u002F assets\u002Fjs\u002Frtafar.media.replacer.min.js:1\nif(\"image\"===e.type){\n    var t=\"image\"===e.type?e.url:e.thumb.src;\n    return'\u003Cdiv class=\"image-item\">\\n                                        \u003Cimg class=\"media-item-'.concat(e.id,'\" data-id=\"').concat(e.id,'\" src=\"').concat(t,'\" alt=\"').concat(e.title,'\" height=\"250px\">\\n                                        \u003Cbutton class=\"button-overlay btn-img-replace\" data-id=\"').concat(e.id,'\">Replace\u003C\u002Fbutton>\\n                                    \u003C\u002Fdiv>')}\n\n---\n\n\u002F\u002F assets\u002Fjs\u002Frtafar.media.replacer.min.js:1\nimagePreview: function(e, t, a) {\n    return '\u003Cimg class=\"media-item-'.concat(e,' preview-image\" data-oldmediaid=\"').concat(e,'\" src=\"').concat(t,'\" alt=\"').concat(a,'\"  \u002F>')\n}\n\n---\n\n\u002F\u002F assets\u002Fjs\u002Frtafar.media.replacer.min.js:1 (inside setupSearchInput)\n.then((function(e){if(\"object\"===r(e.data)&&0!==Object.keys(e.data).length){var t=e.data.map((function(e){ ... })).join(\"\");jQuery(\".image-container\").html(t)}}))","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Freal-time-auto-find-and-replace\u002F1.7.9\u002Fassets\u002Fjs\u002Frtafar.media.replacer.min.js\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Freal-time-auto-find-and-replace\u002F1.8.0\u002Fassets\u002Fjs\u002Frtafar.media.replacer.min.js\n@@ -1 +1 @@\n-(...)\"image\"===e.type){var t=\"image\"===e.type?e.url:e.thumb.src;return'\u003Cdiv class=\"image-item\">\\n                                        \u003Cimg class=\"media-item-'.concat(e.id,'\" data-id=\"').concat(e.id,'\" src=\"').concat(t,'\" alt=\"').concat(e.title,'\" height=\"250px\">\\n                                        \u003Cbutton class=\"button-overlay btn-img-replace\" data-id=\"').concat(e.id,'\">Replace\u003C\u002Fbutton>\\n                                    \u003C\u002Fdiv>')}\n+(...)if(\"object\"===r(t.data)&&0!==Object.keys(t.data).length){var a=jQuery(\".image-container\");a.empty(),t.data.forEach((function(t){var r=jQuery(\"\u003Cdiv\u002F>\",{class:\"image-item\"}),i=jQuery(\"\u003Cbutton\u002F>\",{class:\"button-overlay btn-img-replace\",\"data-id\":t.id,text:\"Replace\"});if(\"image\"===t.type){var o=\"image\"===t.type?t.url:t.thumb.src;r.append(e.imagePreview(t.id,o,t.title,\"250px\"))}else\"video\"===t.type&&r.append(e.videoPreview(t.id,t.url,\"250px\"));r.append(i),a.append(r)}))}","To exploit this vulnerability, an attacker with Author-level access (or any role with `upload_files` capability) follows these steps:\n1. Upload a legitimate image to the WordPress Media Library.\n2. Update the image metadata (Title) via `wp-admin\u002Fpost.php` to include an XSS payload designed to break out of an HTML attribute, such as: `poc\" onerror=\"alert(document.domain)\" x=\"`.\n3. Wait for an administrator to access the plugin's 'Media Replacer' page at `wp-admin\u002Fadmin.php?page=rtafar-media-replacer`.\n4. When the administrator searches for a term matching the malicious image (e.g., 'poc'), the plugin performs an AJAX request (`query-attachments`) and uses jQuery's `.html()` method to render the results.\n5. Because the `title` attribute from the AJAX response is concatenated directly into an `\u003Cimg>` tag's `alt` attribute without escaping, the `onerror` event handler executes the attacker's script in the administrator's browser context.","gemini-3-flash-preview","2026-04-16 15:14:29","2026-04-16 15:15:15",{"type":37,"vulnerable_version":38,"fixed_version":11,"vulnerable_browse":39,"vulnerable_zip":40,"fixed_browse":41,"fixed_zip":42,"all_tags":43},"plugin","1.7.9","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Freal-time-auto-find-and-replace\u002Ftags\u002F1.7.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Freal-time-auto-find-and-replace.1.7.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Freal-time-auto-find-and-replace\u002Ftags\u002F1.8.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Freal-time-auto-find-and-replace.1.8.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Freal-time-auto-find-and-replace\u002Ftags"]