Skip to content

Commit 9ab7ef8

Browse files
committed
Add more rules.
Add ID to rules.
1 parent d20459d commit 9ab7ef8

File tree

2 files changed

+183
-54
lines changed

2 files changed

+183
-54
lines changed

src/Rules/CisRules.php

Lines changed: 60 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,77 +16,133 @@ final class CisRules
1616
* Get all CIS security rules
1717
*
1818
* @return array[] Array of rule definitions with:
19-
* - severity: string (critical/high/medium/low)
20-
* - message: string Description of the vulnerability
21-
* - pattern: string Regex pattern to detect the issue
22-
* - reference: string CIS Benchmark reference
19+
* - id: string Unique identifier for the rule
20+
* - severity: string (critical/high/medium/low)
21+
* - message: string Description of the vulnerability
22+
* - pattern: string Regex pattern to detect the issue
23+
* - reference: string CIS Benchmark reference (optional)
2324
*/
2425
public static function getRules(): array
2526
{
2627
return [
2728
// PHP Configuration (15 rules)
2829
[
30+
'id' => 'CIS-001',
2931
'severity' => 'critical',
3032
'message' => 'CIS-001: Dangerous functions not disabled',
3133
'pattern' => '/disable_functions\s*=\s*[^\n]*(?!(exec|system|passthru|shell_exec|proc_open|popen|eval))/i',
3234
],
3335
[
36+
'id' => 'CIS-002',
3437
'severity' => 'high',
3538
'message' => 'CIS-002: Error reporting exposes stack traces',
3639
'pattern' => '/display_errors\s*\(\s*true\s*\)/i',
3740
],
3841

3942
// File System (20 rules)
4043
[
44+
'id' => 'CIS-003',
4145
'severity' => 'critical',
4246
'message' => 'CIS-003: Directory traversal vulnerability',
4347
'pattern' => '/(include|require)(_once)?\s*\([^)]*\.\.\//i',
4448
],
4549
[
50+
'id' => 'CIS-004',
4651
'severity' => 'high',
4752
'message' => 'CIS-004: Unsafe temporary file creation',
4853
'pattern' => '/tmpfile\s*\(\)|tempnam\s*\(/i',
4954
],
5055

5156
// Sessions (10 rules)
5257
[
58+
'id' => 'CIS-005',
5359
'severity' => 'high',
5460
'message' => 'CIS-005: Session fixation possible',
5561
'pattern' => '/session_start\s*\([^)]*\)\s*;\s*(?!.*session_regenerate_id)/i',
5662
],
5763

5864
// Cryptography (15 rules)
5965
[
66+
'id' => 'CIS-006',
6067
'severity' => 'critical',
6168
'message' => 'CIS-006: Weak hash function detected',
6269
'pattern' => '/(md5|sha1)\s*\(.*password/i',
6370
],
6471
[
72+
'id' => 'CIS-007',
6573
'severity' => 'high',
6674
'message' => 'CIS-007: Hardcoded encryption keys',
6775
'pattern' => '/\$key\s*=\s*[\'"][a-f0-9]{10,}[\'"]/i',
6876
],
6977

7078
// Database (15 rules)
7179
[
80+
'id' => 'CIS-008',
7281
'severity' => 'critical',
7382
'message' => 'CIS-008: Raw SQL with user input',
7483
'pattern' => '/mysql(i)?_query\s*\(.*\$_(GET|POST)/i',
7584
],
7685

7786
// Input Validation (15 rules)
7887
[
88+
'id' => 'CIS-009',
7989
'severity' => 'high',
8090
'message' => 'CIS-009: Unvalidated redirect',
8191
'pattern' => '/header\s*\(\s*[\'"]Location:\s*\'\.\$_(GET|POST)/i',
8292
],
8393

8494
// Network (10 rules)
8595
[
96+
'id' => 'CIS-010',
8697
'severity' => 'high',
8798
'message' => 'CIS-010: SSL verification disabled',
8899
'pattern' => '/curl_setopt\s*\(\s*.*CURLOPT_SSL_VERIFYPEER\s*,\s*false/i',
89100
],
101+
// Dangerous function (extract)
102+
[
103+
'id' => 'CIS-011',
104+
'severity' => 'critical',
105+
'message' => 'CIS-011: Dangerous use of extract() with user input',
106+
'pattern' => '/extract\s*\(\s*\$_(GET|POST|REQUEST|COOKIE|SERVER)/i',
107+
],
108+
// Dangerous file inclusion
109+
[
110+
'id' => 'CIS-012',
111+
'severity' => 'critical',
112+
'message' => 'CIS-012: Potential Remote File Inclusion (RFI)',
113+
'pattern' => '/(include|require|include_once|require_once)\s*\([^)]*\$_(GET|POST|REQUEST)\)/i', // Checks for direct user input in include/require.
114+
],
115+
116+
// Weak randomness
117+
[
118+
'id' => 'CIS-013',
119+
'severity' => 'medium',
120+
'message' => 'CIS-013: Use of weak random number generator (rand)',
121+
'pattern' => '/rand\s*\(\s*\)/i',
122+
],
123+
124+
// Exposing sensitive information in error logs (CIS related)
125+
[
126+
'id' => 'CIS-014',
127+
'severity' => 'high',
128+
'message' => 'CIS-014: Error logging might expose sensitive data',
129+
'pattern' => '/error_log\s*\([^)]*\$_(GET|POST|COOKIE|SERVER|REQUEST)/i', // Checks for user input in error_log.
130+
],
131+
// A simple check for *not* setting httponly
132+
[
133+
'id' => 'CIS-015',
134+
'severity' => 'medium',
135+
'message' => 'CIS-015: Session cookie might lack HttpOnly flag',
136+
'pattern' => '/session_set_cookie_params\s*\([^)]*(?<!HttpOnly)[,)]/i', // Checks if HttpOnly isn't set as an argument (simplistic)
137+
],
138+
139+
// Insecure deserialization
140+
[
141+
'id' => 'CIS-016',
142+
'severity' => 'critical',
143+
'message' => 'CIS-016: Insecure deserialization using unserialize',
144+
'pattern' => '/unserialize\s*\(\s*\$_(GET|POST|COOKIE|REQUEST)/i', // Checks for user input in unserialize.
145+
],
90146
];
91147
}
92148
}

src/Rules/OwaspRules.php

Lines changed: 123 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -3,107 +3,180 @@
33
namespace Yousha\PhpSecurityLinter\Rules;
44

55
/**
6-
* OWASP Security Rules Implementation
6+
* OWASP Top 10 Security Rules Implementation
77
*
8-
* Provides security rules based on OWASP Top 10 and other application security standards
9-
* covering web application vulnerabilities and secure coding practices.
8+
* Provides security rules based on the OWASP Top 10 (2021) list,
9+
* focusing on common, high-impact web application vulnerabilities in PHP.
1010
*
1111
* @package PhpSecurityLinter\Rules
1212
*/
1313
final class OwaspRules
1414
{
1515
/**
16-
* Get all OWASP security rules
16+
* Get all OWASP Top 10 security rules
1717
*
1818
* @return array[] Array of rule definitions with:
19-
* - severity: string (critical/high/medium/low)
20-
* - message: string Description of the vulnerability
21-
* - pattern: string Regex pattern to detect the issue
22-
* - reference: string OWASP standard reference
19+
* - id: string Unique identifier for the rule (e.g., OWASP-001)
20+
* - severity: string (critical/high/medium/low)
21+
* - message: string Description of the vulnerability
22+
* - pattern: string Regex pattern to detect the issue
23+
* - reference: string OWASP A-Code reference (optional)
2324
*/
2425
public static function getRules(): array
2526
{
2627
return [
27-
// A1: Injection (20 rules)
28+
// A03:2021 - Injection (SQL, Command, etc.)
2829
[
30+
'id' => 'OWASP-001',
2931
'severity' => 'critical',
30-
'message' => 'OWASP-A1: SQL Injection (concatenated)',
31-
'pattern' => '/\$sql\s*=\s*["\'].*?\$_(GET|POST)/i',
32+
'message' => 'OWASP-001: SQL Injection risk (unsanitized input in query)',
33+
'pattern' => '/(PDO|mysqli)->query\s*\([^)]*(\$_GET|\$_POST|\$_REQUEST)/i',
34+
'reference' => 'A03:2021',
3235
],
36+
// A03:2021 - Injection (Command)
3337
[
38+
'id' => 'OWASP-002',
3439
'severity' => 'critical',
35-
'message' => 'OWASP-A1: Command Injection',
36-
'pattern' => '/(exec|system|passthru)\s*\(.*\$_(GET|POST)/i',
40+
'message' => 'OWASP-002: OS Command Injection risk (exec/system with unsanitized input)',
41+
'pattern' => '/(exec|shell_exec|passthru|system)\s*\([^)]*(\$_GET|\$_POST|\$_REQUEST)/i',
42+
'reference' => 'A03:2021',
3743
],
38-
39-
// A2: Cryptographic (15 rules)
44+
// A04:2021 - Insecure Design / PHP Object Injection
4045
[
46+
'id' => 'OWASP-003',
4147
'severity' => 'critical',
42-
'message' => 'OWASP-A2: Hardcoded credentials',
43-
'pattern' => '/\$?(user|pass|pwd)\s*=\s*[\'"][^\'"]+[\'"]/i',
48+
'message' => 'OWASP-003: PHP Object Injection risk (unserialize on user input)',
49+
'pattern' => '/unserialize\s*\([^)]*(\$_GET|\$_POST|\$_REQUEST)/i',
50+
'reference' => 'A04:2021',
4451
],
45-
46-
// A3: XSS (15 rules)
52+
// A07:2021 - Identification and Authentication Failures
4753
[
54+
'id' => 'OWASP-004',
55+
'severity' => 'critical',
56+
'message' => 'OWASP-004: Weak password hashing or storing sensitive data in session',
57+
// FIXED: All capture groups are now correctly closed.
58+
'pattern' => '/(hash\s*\([^,]*,\s*password\))|(\$_(SESSION)\s*\[.*(password|key|secret)\])/i',
59+
'reference' => 'A07:2021',
60+
],
61+
// A01:2021 - Broken Access Control
62+
[
63+
'id' => 'OWASP-005',
4864
'severity' => 'high',
49-
'message' => 'OWASP-A3: Reflected XSS',
50-
'pattern' => '/echo\s+\$_(GET|POST)\s*\[.*\]/i',
65+
'message' => 'OWASP-005: File inclusion risk (potential Local File Inclusion)',
66+
'pattern' => '/(include|require)(_once)?\s*\([^)]*(\$_GET|\$_POST|\$_REQUEST)/i',
67+
'reference' => 'A01:2021',
5168
],
52-
53-
// A4: Insecure Design (10 rules)
69+
// A10:2021 - Server-Side Request Forgery (SSRF)
5470
[
71+
'id' => 'OWASP-006',
5572
'severity' => 'high',
56-
'message' => 'OWASP-A4: Missing CSRF protection',
57-
'pattern' => '/<form[^>]*>(?!.*(csrf|_token))/i',
73+
'message' => 'OWASP-006: Server-Side Request Forgery (SSRF) risk',
74+
'pattern' => '/(file_get_contents|curl_exec|fsockopen|guzzle|httpclient)\s*\([^)]*(\$_GET|\$_POST|\$_REQUEST)/i',
75+
'reference' => 'A10:2021',
5876
],
59-
60-
// A5: Misconfig (10 rules)
77+
// A07:2021 - XSS (Cross-Site Scripting)
6178
[
79+
'id' => 'OWASP-007',
6280
'severity' => 'high',
63-
'message' => 'OWASP-A5: Debug mode enabled',
64-
'pattern' => '/define\s*\(\s*[\'"]APP_DEBUG[\'"]\s*,\s*true\s*\)/i',
81+
'message' => 'OWASP-007: Cross-Site Scripting (XSS) risk (unescaped output)',
82+
'pattern' => '/echo\s*(\$_GET|\$_POST|\$_REQUEST)/i',
83+
'reference' => 'A07:2021',
6584
],
66-
67-
// A6: Vulnerable Components (10 rules)
85+
// A02:2021 - Cryptographic Failures
86+
[
87+
'id' => 'OWASP-008',
88+
'severity' => 'medium',
89+
'message' => 'OWASP-008: Use of weak random number generator',
90+
'pattern' => '/(rand|mt_rand)\s*\(/i',
91+
'reference' => 'A02:2021',
92+
],
93+
// A05:2021 - Security Misconfiguration (File Upload)
6894
[
95+
'id' => 'OWASP-009',
96+
'severity' => 'medium',
97+
'message' => 'OWASP-009: Insecure file upload handling (missing validation)',
98+
'pattern' => '/move_uploaded_file\s*\([^)]*\)\s*;\s*(?!.*is_uploaded_file)/i',
99+
'reference' => 'A05:2021',
100+
],
101+
// A05:2021 - Security Misconfiguration (Global Variables)
102+
[
103+
'id' => 'OWASP-010',
104+
'severity' => 'low',
105+
'message' => 'OWASP-010: Accessing raw superglobals directly (security best practice)',
106+
'pattern' => '/(\$_GET|\$_POST|\$_REQUEST|\$_COOKIE|eval)/i',
107+
'reference' => 'A05:2021',
108+
],
109+
// A08:2021 - Software and Data Integrity Failures (CSRF is a related issue)
110+
[
111+
'id' => 'OWASP-011',
69112
'severity' => 'high',
70-
'message' => 'OWASP-A6: Known vulnerable library',
71-
'pattern' => '/(jquery\s+1\.[0-9]|bootstrap\s+3\.[0-3])/i',
113+
'message' => 'OWASP-011: Missing Cross-Site Request Forgery (CSRF) protection',
114+
// Checks for a <form method="post"> tag that doesn't contain a hidden input for a token
115+
'pattern' => '/<form\s+[^>]*method=["\']post["\'][^>]*>(?![^<]*<input[^>]*type=["\']hidden["\'][^>]*name=["\']csrf_token)/i',
116+
'reference' => 'A08:2021',
117+
],
118+
// A05:2021 - Security Misconfiguration (Cookies)
119+
[
120+
'id' => 'OWASP-012',
121+
'severity' => 'medium',
122+
'message' => 'OWASP-012: Insecure cookie flags (missing HttpOnly or Secure)',
123+
// Checks for setcookie() without 'httponly' or 'secure' flags set in the last parameter array or arguments
124+
'pattern' => '/setcookie\s*\([^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*[^)]*,\s*(?!.*(true|secure|httponly))/i',
125+
'reference' => 'A05:2021',
126+
],
127+
// A01:2021 - Path Traversal
128+
[
129+
'id' => 'OWASP-013',
130+
'severity' => 'critical',
131+
'message' => 'OWASP-A01: Path Traversal (Local File Inclusion)',
132+
'pattern' => '/(include|require|file_get_contents|fopen|readfile)\s*\([^)]*["\']?\s*\.\s*\$_(GET|POST|REQUEST)\s*\.\s*["\']?\)/i', // Looks for direct user input concatenated into file operations.
72133
],
73134

74-
// A7: Auth Failures (10 rules)
135+
// A06:2021 - Improper Asset Management - Debug files
75136
[
76-
'severity' => 'high',
77-
'message' => 'OWASP-A7: Weak password policy',
78-
'pattern' => '/min_password_length\s*[<=]\s*6/i',
137+
'id' => 'OWASP-014',
138+
'severity' => 'medium',
139+
'message' => 'OWASP-A06: Potential debug file exposed',
140+
'pattern' => '/\.(log|sql|bak|backup|old|tmp)$/i', // Checks for common debug file extensions.
141+
],
142+
// A07:2021 - Identification and Authentication Failures - Weak Password Hashing
143+
[
144+
'id' => 'OWASP-015',
145+
'severity' => 'critical',
146+
'message' => 'OWASP-A07: Weak password hashing algorithm used',
147+
'pattern' => '/hash\s*\(\s*[\'"](?i)(md2|md4|md5|sha1|sha224)[\'"]/i', // Checks for weak hash functions in hash().
79148
],
80149

81-
// A8: Data Protection (10 rules)
150+
// A08:2021 - Software and Data Integrity Failures - Unserialize
82151
[
152+
'id' => 'OWASP-016',
83153
'severity' => 'critical',
84-
'message' => 'OWASP-A8: Plaintext sensitive data',
85-
'pattern' => '/\$_(POST|GET)\s*\[[\'"]?(credit_card|ssn)[\'"]?\]/i',
154+
'message' => 'OWASP-A08: Insecure deserialization (unserialize)',
155+
'pattern' => '/unserialize\s*\(\s*\$_(GET|POST|COOKIE|REQUEST)/i', // Checks for user input in unserialize (same as CIS-017).
86156
],
87157

88-
// A10: SSRF (10 rules)
158+
// A10:2021 - Server-Side Request Forgery
89159
[
160+
'id' => 'OWASP-017',
90161
'severity' => 'critical',
91-
'message' => 'OWASP-A10: Potential SSRF',
92-
'pattern' => '/file_get_contents\s*\(\s*\$_(GET|POST)/i',
162+
'message' => 'OWASP-A10: Potential Server-Side Request Forgery (SSRF)',
163+
'pattern' => '/(file_get_contents|fopen|curl_init|fsockopen|stream_socket_client)\s*\([^)]*\$_(GET|POST|REQUEST)/i', // Checks for user input in various HTTP/file functions.
93164
],
94165

95-
// API Security (15 rules)
166+
// Cross-Site Scripting (XSS) - Reflected
96167
[
168+
'id' => 'OWASP-018',
97169
'severity' => 'high',
98-
'message' => 'OWASP-API1: Missing rate limiting',
99-
'pattern' => '/function\s+api_\w+\s*\(\)[^{]*\{[^}]*\}(?!.*sleep\s*\(\d+\))/i',
170+
'message' => 'OWASP-A07: Potential Reflected XSS (outputting user input)',
171+
'pattern' => '/echo\s+\$_(GET|POST|REQUEST|COOKIE)/i', // Checks for direct output of user input.
100172
],
101173

102-
// Cloud (10 rules)
174+
// A08:2021 - Insecure Deserialization - Alternative pattern
103175
[
104-
'severity' => 'high',
105-
'message' => 'OWASP-CLOUD1: Hardcoded AWS keys',
106-
'pattern' => '/\$aws_(key|secret)\s*=\s*[\'"][^\'"]+[\'"]/i',
176+
'id' => 'OWASP-019',
177+
'severity' => 'critical',
178+
'message' => 'OWASP-A08: Potential Insecure Deserialization (serialize/unserialize mismatch)',
179+
'pattern' => '/serialize\s*\(\s*\$_(GET|POST|REQUEST)/i', // Checks for serializing user input (less common than unserialize).
107180
],
108181
];
109182
}

0 commit comments

Comments
 (0)