XSS Vulnerability in LiteSpeed Cache Plugin Affecting 4+ Million Sites
Security Advisories
Featured
xss
LiteSpeed Cache
Published 27 February 2024 Rafie Muhammad Security Researcher at Patchstack Table of Contents
LiteSpeed Cache
Unauthenticated Site Wide Stored XSS
This blog post is about the LiteSpeed plugin vulnerability. If you’re a LiteSpeed user, please update the plugin to at least version 5.7.0.1.
Patchstack Developer and Business users are protected from the vulnerability. You can also sign up for the Patchstack Community plan to be notified about vulnerabilities as soon as they become disclosed.
For plugin developers, we have security audit services and Threat Intelligence Feed API for hosting companies.
About the LiteSpeed Cache Plugin
The plugin LiteSpeed Cache (free version), which has over 4 million active installations, is known as the most popular caching plugin in WordPress.
This WordPress plugin is an all-in-one site acceleration plugin, featuring an exclusive server-level cache and a collection of optimization features. The plugin supports WordPress Multisite and is compatible with the most popular plugins, including WooCommerce, bbPress, and Yoast SEO.
The security vulnerability
This plugin suffers from unauthenticated site-wide stored XSS vulnerability and could allow any unauthenticated user from stealing sensitive information to, in this case, privilege escalation on the WordPress site by performing a single HTTP request.
This vulnerability occurs because the code that handles input from the user doesn’t implement sanitization and output escaping. This case also combined with improper access control on one of the available REST API endpoints from the plugin. The described vulnerability was fixed in version 5.7.0.1 and assigned CVE-2023-40000.
The main vulnerability exists in the function update_cdn_status
:
/**
* Callback for updating Auto CDN Setup status after run
*
* @since 4.7
* @access public
*/
public function update_cdn_status() {
if ( !isset( $_POST[ 'success' ] ) || !isset( $_POST[ 'result' ] ) ) {
self::save_summary( array( 'cdn_setup_err'=> __( 'Received invalid message from the cloud server. Please submit a ticket.', 'litespeed-cache' ) ) );
return self::err( 'lack_of_param' );
}
if (!$_POST[ 'success' ]) {
self::save_summary( array( 'cdn_setup_err'=> $_POST[ 'result' ][ '_msg' ] ) );
Admin_Display::error( __( 'There was an error during CDN setup: ', 'litespeed-cache' ) . $_POST[ 'result' ][ '_msg' ] );
} else {
$this->_process_cdn_status($_POST[ 'result' ]);
}
return self::ok();
}
This function is called from cdn_status
function:
/**
* Endpoint for QC to notify plugin of CDN setup status update.
*
* @since 3.0
*/
public function cdn_status() {
return $this->cls( 'Cdn_Setup' )->update_cdn_status();
}
The cdn_status
itself is confirmed as a function handler for litespeed/v1/cdn_status
REST API endpoint :
// CDN setup callback notification
register_rest_route( 'litespeed/v1', '/cdn_status', array(
'methods'=> 'POST',
'callback'=> array( $this, 'cdn_status' ),
'permission_callback' => array( $this, 'is_from_cloud' ),
) );
The endpoint is protected by is_from_cloud
which is set as the permission_callback
argument that should check the user permission that accessed the specified endpoint. Turns out that this function only returns true
which would allow any unauthenticated user to access the endpoint :
/**
* Check if the request is from cloud nodes
*
* @since 4.2
* @since 4.4.7 As there is always token/api key validation, ip validation is redundant
*/
public function is_from_cloud() {
return true;
// return $this->cls( 'Cloud' )->is_from_cloud();
}
Back to the update_cdn_status
function, one of the condition sets could make the function trigger Admin_Display::error()
function with unsanitized $_POST[ 'result' ][ '_msg' ]
parameter supplied as the input parameter.
The Admin_Display::error()
function itself is just a wrapper function to display an admin notice, which in WordPress context is a message to display information, alerts, and messages to users inside of the wp-admin
area.
Function update_cdn_status
could also trigger a call to _process_cdn_status
function :
/**
* Process the returned Auto CDN Setup status
*
* @since 4.7
* @access private
*/
private function _process_cdn_status($result) {
if ( isset($result[ 'nameservers' ] ) ) {
if (isset($this->_summary['cdn_setup_err'])) {
unset($this->_summary['cdn_setup_err']);
}
if (isset($result[ 'summary' ])) {
$this->_summary[ 'cdn_dns_summary' ]=$result[ 'summary' ];
}
$this->cls( 'Cloud' )->set_linked();
$this->cls( 'Conf' )->update_confs( array( self::O_QC_NAMESERVERS=> $result[ 'nameservers' ], self::O_CDN_QUIC=> true ) );
Admin_Display::succeed( '🎊 ' . __( 'Congratulations, QUIC.cloud successfully set this domain up for the CDN. Please update your nameservers to:', 'litespeed-cache' ) . $result[ 'nameservers' ] );
} else if ( isset($result[ 'done' ] ) ) {
if ( isset( $this->_summary[ 'cdn_setup_err' ] ) ) {
unset( $this->_summary[ 'cdn_setup_err' ] );
}
if ( isset( $this->_summary[ 'cdn_verify_msg' ] ) ) {
unset( $this->_summary[ 'cdn_verify_msg' ] );
}
$this->_summary[ 'cdn_setup_done_ts' ]=time();
$this->_setup_token='';
$this->cls( 'Conf' )->update_confs( array( self::O_QC_TOKEN=> '', self::O_QC_NAMESERVERS=> '' ) );
} else if ( isset($result[ '_msg' ] ) ) {
$notice=$result[ '_msg' ];
if ( $this->conf( Base::O_QC_NAMESERVERS )) {
$this->_summary[ 'cdn_verify_msg' ]=$result[ '_msg' ];
$notice=array('cdn_verify_msg'=> $result[ '_msg' ]);
}
Admin_Display::succeed( $notice );
} else {
Admin_Display::succeed( __( 'CDN Setup is running.', 'litespeed-cache' ) );
}
self::save_summary();
}
The $result
the variable itself is an unsanitized value of $_POST[ 'result' ]
parameter. Similar to the condition in update_cdn_status
, it utilizes Admin_Display::succeed()
function which is the same process as Admin_Display::error()
function and only differs on the type of success or error message.
Note that this vulnerability is reproducible in a default installation and activation of the LiteSpeed Cache plugin without a specific requirement or configuration. Since the XSS payload is placed as an admin notice and the admin notice could be displayed on any wp-admin
endpoint, this vulnerability also could be easily triggered by any user that has access to the wp-admin
area.
The patch
Since this vulnerability exists because the code constructs an HTML value directly from the POST body
parameter to the admin notice message, sanitizing user input using esc_html
directly on the affected parameter should be enough to fix the issue. Additionally, the vendor also added a permission check on the update_cdn_status
function via hash validation to limit the access to the function to only privileged users. The patch can be seen below:
Conclusion
We recommend applying escaping and sanitization to any message that will be displayed as an admin notice. Depending on the context of the data, we recommend using sanitize_text_field to sanitize value for HTML output (outside of HTML attribute) or esc_html. For escaping values inside of attributes, you can use the esc_attr function. We also recommend applying a proper permission or authorization check to the registered rest route endpoints.
Help us make the Internet a safer place
Making the WordPress ecosystem more secure is a team effort, and we believe that plugin developers and security researchers should work together.
- If you’re a plugin developer, join our mVDP program that makes it easier to report, manage and address vulnerabilities in your software.
- If you’re a security researcher, join Patchstack Alliance to report vulnerabilities & earn rewards.
Found this useful? Share on
Detect vulnerabilities and protect your WordPress apps. See features
Weekly security advice
Get the latest WordPress security intelligence delivered to your inbox.
Email Signup Subscribe
The latest in Security Advisories
Critical RCE Patched in Bricks Builder Theme
Bricks Builder
31 January, 2024
WordPress 6.4.3 Security Release
wordpress
9 January, 2024
AI Engine Plugin Affected by Critical Vulnerability
Critical Vulnerability
arbitrary file upload
AI Engine
Protection
Pricing WordPress For agencies Documentation
Solutions
WordPress security Plugin auditing Managed VDP Bug bounty Intelligence (API)
Bug bounty
Leaderboard Security programs Guidelines Report
Resources
Vulnerability database WordPress statistics
Whitepaper 2022 Articles Join Discord
Patchstack
Careers Media kit LinkedIn Facebook X © 2024 Patchstack DPA Privacy Policy Terms & Conditions
Protection
Pricing WordPress For agencies Documentation
Solutions
WordPress security Plugin auditing Managed VDP Bug bounty Intelligence (API)
Bug bounty
Leaderboard Security programs Guidelines Report
Resources
Vulnerability database WordPress statistics
Whitepaper 2022 Articles Join Discord
Patchstack
Careers Media kit LinkedIn Facebook X © 2024 Patchstack DPA Privacy Policy Terms & Conditions
This website uses cookies. Learn more.
Looks like your browser is blocking our support chat widget. Turn off adblockers and reload the page. Reload page
close chevron-down chain bars angle-right angle-up cross menu
Source: patchstack.com