Reduce XSS false positives for safe URL helpers and model IDs
Skip XSS detection for: - Safe URL helpers: route(), url(), asset(), secure_asset(), secure_url(), static_url(), action(), mix(), vite() - Null coalesce with safe helpers: $var ?? url(...) - Model ID patterns: $model->id (typically safe integers) These patterns are unlikely to be user-controllable and create noise that obscures real vulnerabilities. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -257,8 +257,22 @@ class XssRule extends BaseRule
|
|||||||
$attrName = strtolower($urlMatches[1][$i][0]);
|
$attrName = strtolower($urlMatches[1][$i][0]);
|
||||||
$expression = trim($match[0]);
|
$expression = trim($match[0]);
|
||||||
|
|
||||||
// Skip if it's clearly a route or URL helper
|
// Skip if it's clearly a safe URL helper (route, url, asset, etc.)
|
||||||
if (preg_match('/^\s*(route|url|asset|secure_asset|action)\s*\(/', $expression)) {
|
// These generate URLs from application config, not user input
|
||||||
|
if (preg_match('/^\s*(route|url|asset|secure_asset|secure_url|static_url|action|mix|vite)\s*\(/', $expression)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if expression uses null coalesce with safe helpers
|
||||||
|
if (preg_match('/\?\?\s*(route|url|asset|secure_asset|secure_url|static_url|action|mix|vite)\s*\(/', $expression)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if expression only contains model ID access patterns (e.g., $model->id)
|
||||||
|
// These are typically safe integers from the database
|
||||||
|
if (preg_match('/^[\s\w\$\-\>\.\'\"\/\(\),]+$/', $expression) &&
|
||||||
|
preg_match('/\$\w+->id\b/', $expression) &&
|
||||||
|
!preg_match('/\$_(GET|POST|REQUEST|COOKIE|SERVER)/', $expression)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,11 +299,32 @@ class XssRule extends BaseRule
|
|||||||
$eventMatches = [1 => array_merge($eventMatchesDouble[1], $eventMatchesSingle[1])];
|
$eventMatches = [1 => array_merge($eventMatchesDouble[1], $eventMatchesSingle[1])];
|
||||||
|
|
||||||
foreach ($eventMatches[1] as $match) {
|
foreach ($eventMatches[1] as $match) {
|
||||||
|
$expression = trim($match[0]);
|
||||||
|
|
||||||
|
// Skip if it's clearly a safe URL helper (route, url, asset, etc.)
|
||||||
|
// These generate URLs from application config, not user input
|
||||||
|
if (preg_match('/^\s*(route|url|asset|secure_asset|secure_url|static_url|action|mix|vite)\s*\(/', $expression)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if expression uses null coalesce with safe helpers
|
||||||
|
if (preg_match('/\?\?\s*(route|url|asset|secure_asset|secure_url|static_url|action|mix|vite)\s*\(/', $expression)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if expression only contains model ID access patterns (e.g., $model->id)
|
||||||
|
// These are typically safe integers from the database
|
||||||
|
if (preg_match('/^[\s\w\$\-\>\.\'\"\/\(\),]+$/', $expression) &&
|
||||||
|
preg_match('/\$\w+->id\b/', $expression) &&
|
||||||
|
!preg_match('/\$_(GET|POST|REQUEST|COOKIE|SERVER)/', $expression)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$line = $this->getLineFromOffset($content, $match[1]);
|
$line = $this->getLineFromOffset($content, $match[1]);
|
||||||
$vulnerabilities[] = $this->createVulnerability(
|
$vulnerabilities[] = $this->createVulnerability(
|
||||||
'XSS',
|
'XSS',
|
||||||
Vulnerability::SEVERITY_HIGH,
|
Vulnerability::SEVERITY_HIGH,
|
||||||
$this->msg('xss.event_handler', ['expr' => trim($match[0])]),
|
$this->msg('xss.event_handler', ['expr' => $expression]),
|
||||||
$filePath,
|
$filePath,
|
||||||
$line,
|
$line,
|
||||||
null,
|
null,
|
||||||
|
|||||||
Reference in New Issue
Block a user