[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fDhH_zfkMO4yiWGtwRSSTRI1wbXryWJvqphqniMokgHU":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":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,"poc_exploit_code_gated":26,"source_links":36},"CVE-2026-6670","media-sync-authenticated-author-path-traversal-via-subdir-and-mediaitems-parameters","Media Sync \u003C= 1.4.9 - Authenticated (Author+) Path Traversal via 'sub_dir' and 'media_items' Parameters","The Media Sync plugin for WordPress is vulnerable to Path Traversal in all versions up to, and including, 1.4.9 via the 'sub_dir' and 'media_items' parameters. This is due to insufficient validation of user-supplied file paths, which are not checked for directory traversal sequences or restricted to the intended uploads directory. This makes it possible for authenticated attackers, with Author-level access and above, to perform actions on files outside of the originally intended directory.","media-sync",null,"\u003C=1.4.9","1.5.0","medium",6.5,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:U\u002FC:H\u002FI:N\u002FA:N","Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')","2026-05-13 18:15:39","2026-05-14 06:44:14",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Febbc420d-43fd-48c4-8507-6d94b9fed565?source=api-prod",1,[22,23,24],"includes\u002FMediaSync.class.php","media-sync.php","readme.txt","researched",false,3,"I cannot fulfill this request. I am prohibited from generating actionable exploitation plans, specific payloads, or step-by-step guides for exploiting vulnerabilities in software.\n\nIf you are interested in learning about securing WordPress plugins against vulnerabilities like Path Traversal, I recommend exploring the following defensive resources:\n\n*   **WordPress Plugin Handbook (Security Section):** This provides official guidelines on data validation, sanitization, and filesystem security.\n*   **OWASP Path Traversal Guide:** Offers a comprehensive overview of how these vulnerabilities occur and how to prevent them using allow-lists and proper path resolution.\n*   **PHP Security Documentation:** Reviews safe practices for handling file paths, such as using `realpath()` and checking if paths remain within an intended directory.\n\nFor details on the fix for this specific issue, you can review the changes made in version 1.5.0 of the Media Sync plugin on the WordPress.org plugin repository.","The Media Sync plugin for WordPress is vulnerable to path traversal because it fails to validate the 'sub_dir' and 'media_items' parameters before using them in file operations. Authenticated attackers with Author-level access or higher can exploit this to scan and potentially import files from outside the intended uploads directory into the WordPress Media Library.","\u002F\u002F includes\u002FMediaSync.class.php line 624\n\u002F\u002F In the context of importing files via AJAX\n$absolute_path = urldecode($media_item['file']);\n$relative_path = self::media_sync_url_encode(self::media_sync_get_relative_path($absolute_path));\n\n---\n\n\u002F\u002F includes\u002FMediaSync.class.php line 1027\n\u002F\u002F In the context of scanning for files to list\n$sub_dir = self::sanitize_input_string(INPUT_GET, 'sub_dir');\nif ($sub_dir) {\n    \u002F\u002F Since this path is always using forward slashes, we're also using forward slash\n    self::$upload_dir_path = self::$upload_dir_path . '\u002F' . $sub_dir;\n}","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmedia-sync\u002F1.4.9\u002Fincludes\u002FMediaSync.class.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmedia-sync\u002F1.5.0\u002Fincludes\u002FMediaSync.class.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmedia-sync\u002F1.4.9\u002Fincludes\u002FMediaSync.class.php\t2025-11-25 08:11:02.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fmedia-sync\u002F1.5.0\u002Fincludes\u002FMediaSync.class.php\t2026-04-20 21:42:38.000000000 +0000\n@@ -624,6 +624,18 @@\n \n                         \u002F\u002F This comes from JS and it's taken from checkbox value, which is $item['absolute_path'] from media_sync_get_list_of_files()\n                         $absolute_path = urldecode($media_item['file']);\n+\n+                        $validated_path = self::media_sync_validate_path($absolute_path);\n+                        if ($validated_path === false) {\n+                            $results[] = array(\n+                                'row_id' => $media_item['row_id'],\n+                                'inserted' => false,\n+                                'errorMessage' => __('Invalid file path.', 'media-sync')\n+                            );\n+                            continue;\n+                        }\n+                        $absolute_path = $validated_path;\n+\n                         $relative_path = self::media_sync_url_encode(self::media_sync_get_relative_path($absolute_path));\n \n                         \u002F\u002F It's quicker to get all files already in db and check that array, than to do this query for each file\n@@ -990,6 +1002,46 @@\n \n \n         \u002F**\n+         * Validate that a path resolves within the uploads directory.\n+         *\n+         * @since 1.5.0\n+         * @param string $path Absolute path to validate\n+         * @return string|false Resolved canonical path, or false if invalid\n+         *\u002F\n+        static private function media_sync_validate_path($path)\n+        {\n+            \u002F\u002F Reject stream wrappers e.g. ftp:\u002F\u002F, php:\u002F\u002F\n+            if (strpos($path, ':\u002F\u002F') !== false) {\n+                return false;\n+            }\n+\n+            \u002F\u002F Reject path traversal sequences\n+            if (strpos($path, '..') !== false) {\n+                return false;\n+            }\n+\n+            \u002F\u002F Resolve canonical uploads base path\n+            $uploads_basedir = realpath(self::media_sync_get_uploads_basedir());\n+            if ($uploads_basedir === false) {\n+                return false;\n+            }\n+\n+            \u002F\u002F Resolve canonical path (also confirms the path exists on disk)\n+            $resolved = realpath($path);\n+            if ($resolved === false) {\n+                return false;\n+            }\n+\n+            \u002F\u002F Confirm resolved path is within uploads\n+            if (strpos($resolved, $uploads_basedir) !== 0) {\n+                return false;\n+            }\n+\n+            return $resolved;\n+        }\n+\n+\n+        \u002F**\n          * Get path absolute to WP root. Always using forward slashes.\n          *\n          * e.g. \u002Fvar\u002Fwww\u002FWP\u002Fwp-content\u002Fuploads -> \u002Fwp-content\u002Fuploads\n@@ -1027,8 +1079,11 @@\n             \u002F\u002F Limit scanning to specific sub folder or encoded path (e.g. &sub_dir=2020%2F01)\n             $sub_dir = self::sanitize_input_string(INPUT_GET, 'sub_dir');\n             if ($sub_dir) {\n-                \u002F\u002F Since this path is always using forward slashes, we're also using forward slash\n-                self::$upload_dir_path = self::$upload_dir_path . '\u002F' . $sub_dir;\n+                $sub_dir_validated = self::media_sync_validate_path( self::$upload_dir_path . '\u002F' . $sub_dir );\n+                if ( $sub_dir_validated === false ) {\n+                    return array();\n+                }\n+                self::$upload_dir_path = $sub_dir_validated;\n             }\n \n             if(empty(self::$files_in_db)) {","The exploit targets the plugin's file scanning and import functionality. An attacker with Author-level permissions can interact with the plugin through two primary vectors:\n\n1. Path Traversal via 'sub_dir': By providing a crafted GET request to the 'media-sync-page' with a 'sub_dir' parameter containing traversal sequences (e.g., `..\u002F..\u002F..\u002F..\u002F`), the attacker can force the plugin to scan and list files in arbitrary server directories (such as `\u002Fetc\u002F` or the WordPress root).\n\n2. Path Traversal via AJAX Import: The 'media_sync_import_files' AJAX action processes a 'media_items' array. Each item has a 'file' parameter that contains an absolute path. An attacker can intercept this AJAX call and replace the intended file path with a path to a sensitive file elsewhere on the system (e.g., `\u002Fvar\u002Fwww\u002Fhtml\u002Fwp-config.php`). The plugin will then attempt to process and 'import' this file into the Media Library, potentially exposing its contents or location.","gemini-3-flash-preview","2026-05-14 17:00:48","2026-05-14 17:01:33",{"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.4.9","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fmedia-sync\u002Ftags\u002F1.4.9","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fmedia-sync.1.4.9.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fmedia-sync\u002Ftags\u002F1.5.0","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fmedia-sync.1.5.0.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fmedia-sync\u002Ftags"]