Skip to content

Commit 6ed3fc2

Browse files
author
Hai Zheng
committed
v7.9.2-b2: * **Security** Validated settings written to .htaccess to prevent directive injection.
1 parent c7f87b4 commit 6ed3fc2

3 files changed

Lines changed: 37 additions & 3 deletions

File tree

litespeed-cache.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: LiteSpeed Cache
44
* Plugin URI: https://www.litespeedtech.com/products/cache-plugins/wordpress-acceleration
55
* Description: High-performance page caching and site optimization from LiteSpeed
6-
* Version: 7.9.2-b1
6+
* Version: 7.9.2-b2
77
* Author: LiteSpeed Technologies
88
* Author URI: https://www.litespeedtech.com
99
* License: GPLv3
@@ -35,7 +35,7 @@
3535
return;
3636
}
3737

38-
! defined( 'LSCWP_V' ) && define( 'LSCWP_V', '7.9.2-b1' );
38+
! defined( 'LSCWP_V' ) && define( 'LSCWP_V', '7.9.2-b2' );
3939

4040
! defined( 'LSCWP_CONTENT_DIR' ) && define( 'LSCWP_CONTENT_DIR', WP_CONTENT_DIR );
4141
! defined( 'LSCWP_DIR' ) && define( 'LSCWP_DIR', __DIR__ . '/' ); // Full absolute path '/var/www/html/***/wp-content/plugins/litespeed-cache/' or MU

readme.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ Please don't report a suspected vulnerability in this support forum. Reporting d
263263
== Changelog ==
264264

265265
= 8.0 - Coming soon 2026 =
266+
* **Security** Validated settings written to .htaccess to prevent directive injection.
266267
* 🌱**OptiMax** OptiMax to maximize the page score.
267268
* **CDN** Kept the saved Cloudflare zone when the API lookup fails after a plugin update. (nathaningram)
268269
* **Cache** Bypassed cache for REST requests authenticated by HTTP credentials such as Application Passwords. (Ionut Platon #419630)

src/htaccess.cls.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,15 @@ class Htaccess extends Root {
113113
const MARKER_START = ' start ###';
114114
const MARKER_END = ' end ###';
115115

116+
/**
117+
* Allowlists for values written into .htaccess directives: cookie names, `-qs:` keys, regex literals.
118+
*
119+
* @since 7.9.2
120+
*/
121+
const PATTERN_COOKIE_NAME = '/^,?[A-Za-z0-9!#&\'*+\-.^_`|~]+\z/';
122+
const PATTERN_DROP_QS = '/^[A-Za-z0-9_.*\-]+\z/';
123+
const PATTERN_REGEX_LITERAL = '/^[^\x00-\x1F\x7F"\'\\\\]+\z/';
124+
116125
/**
117126
* Initialize the class and set its properties.
118127
*
@@ -152,7 +161,7 @@ public function __construct() {
152161
self::LS_MODULE_REWRITE_START, // <IfModule mod_rewrite.c>
153162
self::REWRITE_ON, // RewriteEngine on
154163
'RewriteRule ' . preg_quote(LITESPEED_DATA_FOLDER) . '/debug/.*\.log$ - [F,L]', // phpcs:ignore WordPress.PHP.PregQuoteDelimiter.Missing
155-
'RewriteRule ' . preg_quote(self::CONF_FILE) . ' - [F,L]', // phpcs:ignore WordPress.PHP.PregQuoteDelimiter.Missing
164+
'RewriteRule (^|/)\.litespeed_conf\. - [F,L]',
156165
self::LS_MODULE_END, // </IfModule>
157166
];
158167

@@ -578,6 +587,26 @@ private function _cors_rules() {
578587
);
579588
}
580589

590+
/**
591+
* Keep only the entries of a list setting that may be written into a .htaccess directive.
592+
*
593+
* @since 7.9.2
594+
* @param mixed $values Setting value.
595+
* @param string $pattern Allowlist regex an entry must match in full.
596+
* @return array
597+
*/
598+
private function _htaccess_list( $values, $pattern ) {
599+
$clean = [];
600+
foreach ( (array) $values as $v ) {
601+
if ( is_string( $v ) && preg_match( $pattern, trim( $v ) ) ) {
602+
$clean[] = trim( $v );
603+
} else {
604+
self::debug( 'Dropped an invalid .htaccess list entry' );
605+
}
606+
}
607+
return array_values( array_unique( $clean ) );
608+
}
609+
581610
/**
582611
* Generate rewrite rules based on settings.
583612
*
@@ -588,6 +617,9 @@ private function _cors_rules() {
588617
* @return array{0:array<int,string>,1:array<int,string>,2:array<int,string>,3:array<int,string>} Rules arrays [frontend_ls, backend_ls, frontend_nonls, backend_nonls].
589618
*/
590619
private function _generate_rules( $cfg ) {
620+
foreach ( [ Base::O_CACHE_MOBILE_RULES => self::PATTERN_REGEX_LITERAL, Base::O_CACHE_EXC_COOKIES => self::PATTERN_REGEX_LITERAL, Base::O_CACHE_EXC_USERAGENTS => self::PATTERN_REGEX_LITERAL, Base::O_CACHE_DROP_QS => self::PATTERN_DROP_QS ] as $list_id => $pattern ) {
621+
$cfg[ $list_id ] = $this->_htaccess_list( isset( $cfg[ $list_id ] ) ? $cfg[ $list_id ] : [], $pattern );
622+
}
591623
$new_rules = array();
592624
$new_rules_nonls = array();
593625
$new_rules_backend = array();
@@ -644,6 +676,7 @@ private function _generate_rules( $cfg ) {
644676
}
645677
}
646678
$vary_cookies = apply_filters( 'litespeed_vary_cookies', $vary_cookies ); // todo: test if response vary header can work in latest OLS, drop the above two lines.
679+
$vary_cookies = $this->_htaccess_list( $vary_cookies, self::PATTERN_COOKIE_NAME );
647680
// frontend and backend.
648681
if ( $vary_cookies ) {
649682
$env = 'Cache-Vary:' . implode( ',', $vary_cookies );

0 commit comments

Comments
 (0)