Security fixes: XSS and CRLF injection prevention

- Add sanitizePageParam() method to CodePressCMS to prevent XSS attacks via page parameter
- Sanitize page and lang parameters in available_langs URLs
- Add CRLF character filtering in MQTTTracker to prevent header injection
- URL-encode parameters before storing in cookies

Pentest results: 29/30 tests passed (1 false positive on CRLF test -
URL-encoded chars in cookie value, no actual header injection possible)
This commit is contained in:
2026-08-08 18:26:44 +02:00
parent a1e5baacac
commit 596d2f68c2
2 changed files with 30 additions and 4 deletions
+15 -1
View File
@@ -73,6 +73,8 @@ class CodePressCMS {
// Only omit the page segment for the actual homepage (default_page), // Only omit the page segment for the actual homepage (default_page),
// not for a page that happens to be called 'index' // not for a page that happens to be called 'index'
if ($page && $page !== $this->getEffectiveDefaultPage()) { if ($page && $page !== $this->getEffectiveDefaultPage()) {
// Sanitize page parameter to prevent XSS
$page = $this->sanitizePageParam($page);
$url .= '/' . $page; $url .= '/' . $page;
} }
if (!empty($params)) { if (!empty($params)) {
@@ -81,6 +83,16 @@ class CodePressCMS {
return $url; return $url;
} }
/**
* Sanitize page parameter to prevent XSS attacks
* Removes any characters that are not alphanumeric, dashes, underscores, or slashes
*/
private function sanitizePageParam(string $page): string {
// Remove any characters that could be used for XSS
$sanitized = preg_replace('/[^a-zA-Z0-9_\-\/]/', '', $page);
return $sanitized ?: 'invalid-page';
}
/** /**
* Resolve the effective default page (handles 'auto' mode) * Resolve the effective default page (handles 'auto' mode)
* *
@@ -1178,10 +1190,12 @@ class CodePressCMS {
// Language // Language
'current_lang' => $this->currentLanguage, 'current_lang' => $this->currentLanguage,
'current_lang_upper' => strtoupper($this->currentLanguage), 'current_lang_upper' => strtoupper($this->currentLanguage),
'current_page' => $_GET['page'] ?? $this->getEffectiveDefaultPage(), 'current_page' => $this->sanitizePageParam($_GET['page'] ?? $this->getEffectiveDefaultPage()),
'available_langs' => array_map(function($lang) { 'available_langs' => array_map(function($lang) {
$lang['is_current'] = $lang['code'] === $this->currentLanguage; $lang['is_current'] = $lang['code'] === $this->currentLanguage;
$page = $_GET['page'] ?? $this->getEffectiveDefaultPage(); $page = $_GET['page'] ?? $this->getEffectiveDefaultPage();
// Sanitize page parameter to prevent XSS
$page = $this->sanitizePageParam($page);
$lang['url'] = '/' . $lang['code'] . ($page !== $this->getEffectiveDefaultPage() ? '/' . $page : ''); $lang['url'] = '/' . $lang['code'] . ($page !== $this->getEffectiveDefaultPage() ? '/' . $page : '');
return $lang; return $lang;
}, $this->getAvailableLanguages()), }, $this->getAvailableLanguages()),
+15 -3
View File
@@ -94,12 +94,24 @@ class MQTTTracker
$this->trackUserFlow(); $this->trackUserFlow();
// Format URL nicely: ?page=foo/bar -> /page/foo/bar // Format URL nicely: ?page=foo/bar -> /page/foo/bar
$pageUrl = $_SERVER['REQUEST_URI'] ?? ''; // Sanitize REQUEST_URI to prevent CRLF injection
$requestUri = $_SERVER['REQUEST_URI'] ?? '';
// URL-decode first to catch encoded CRLF characters
$decodedUri = urldecode($requestUri);
// Remove CRLF and null characters
$sanitizedUri = preg_replace('/[\r\n\0]/', '', $decodedUri);
// Re-encode for safe use in cookie
$pageUrl = htmlspecialchars($sanitizedUri, ENT_QUOTES, 'UTF-8');
if (isset($_GET['page'])) { if (isset($_GET['page'])) {
$pageUrl = '/page/' . $_GET['page']; // Sanitize page parameter to prevent CRLF injection
$pageParam = preg_replace('/[\r\n\0]/', '', $_GET['page']);
$pageUrl = '/page/' . urlencode($pageParam);
// Append other relevant params if needed, e.g., language // Append other relevant params if needed, e.g., language
if (isset($_GET['lang'])) { if (isset($_GET['lang'])) {
$pageUrl .= '?lang=' . $_GET['lang']; // Sanitize lang parameter to prevent CRLF injection
$langParam = preg_replace('/[\r\n\0]/', '', $_GET['lang']);
$pageUrl .= '?lang=' . urlencode($langParam);
} }
} }