Simplify XSS safe pattern: check for e() anywhere in expression

Instead of checking for specific patterns like nl2br(e($var)),
now checks if e(), htmlspecialchars(), or htmlentities() appears
anywhere in the expression.

This covers more use cases:
- {!! e($var) !!}
- {!! nl2br(e($var)) !!}
- {!! wordwrap(e($var), 80) !!}
- {!! str_replace('x', 'y', e($var)) !!}

Still flags expressions with escape-breaking functions:
- {!! html_entity_decode(e($var)) !!} -> flagged

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-01-31 19:04:44 +09:00
parent 4951b0b557
commit 5356f7d2f8

View File

@@ -493,13 +493,25 @@ class XssRule extends BaseRule
'/^\s*action\s*\(/', // action() helper '/^\s*action\s*\(/', // action() helper
'/^\s*mix\s*\(/', // mix() helper (Laravel Mix) '/^\s*mix\s*\(/', // mix() helper (Laravel Mix)
'/^\s*vite\s*\(/', // vite() helper (Vite) '/^\s*vite\s*\(/', // vite() helper (Vite)
// nl2br with e() - common safe pattern for displaying user text with line breaks
// e() escapes HTML first, then nl2br() adds <br> tags
'/^\s*nl2br\s*\(\s*e\s*\(/', // nl2br(e($var))
'/^\s*nl2br\s*\(\s*htmlspecialchars\s*\(/', // nl2br(htmlspecialchars($var))
'/^\s*nl2br\s*\(\s*htmlentities\s*\(/', // nl2br(htmlentities($var))
]; ];
// Check if expression contains escape functions (e, htmlspecialchars, htmlentities)
// If escaped and no escape-breaking functions, it's safe
if (preg_match('/\b(e|htmlspecialchars|htmlentities)\s*\(/', $expression)) {
// Make sure no escape-breaking functions are used
$escapeBreakers = ['html_entity_decode', 'htmlspecialchars_decode', 'urldecode', 'rawurldecode'];
$hasEscapeBreaker = false;
foreach ($escapeBreakers as $breaker) {
if (stripos($expression, $breaker) !== false) {
$hasEscapeBreaker = true;
break;
}
}
if (!$hasEscapeBreaker) {
return true;
}
}
foreach ($safePatterns as $pattern) { foreach ($safePatterns as $pattern) {
if (preg_match($pattern, $expression)) { if (preg_match($pattern, $expression)) {
return true; return true;