@sun-asterisk/sunlint 1.3.6 โ 1.3.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -1
- package/config/defaults/default.json +2 -1
- package/config/rule-analysis-strategies.js +20 -0
- package/config/rules/enhanced-rules-registry.json +230 -43
- package/core/analysis-orchestrator.js +9 -5
- package/core/file-targeting-service.js +83 -7
- package/core/performance-optimizer.js +8 -2
- package/package.json +1 -1
- package/rules/common/C065_one_behavior_per_test/analyzer.js +851 -0
- package/rules/common/C065_one_behavior_per_test/config.json +95 -0
- package/rules/common/C073_validate_required_config_on_startup/README.md +110 -0
- package/rules/common/C073_validate_required_config_on_startup/analyzer.js +770 -0
- package/rules/common/C073_validate_required_config_on_startup/config.json +46 -0
- package/rules/common/C073_validate_required_config_on_startup/symbol-based-analyzer.js +370 -0
- package/rules/security/S037_cache_headers/README.md +128 -0
- package/rules/security/S037_cache_headers/analyzer.js +263 -0
- package/rules/security/S037_cache_headers/config.json +50 -0
- package/rules/security/S037_cache_headers/regex-based-analyzer.js +463 -0
- package/rules/security/S037_cache_headers/symbol-based-analyzer.js +546 -0
- package/rules/security/S038_no_version_headers/README.md +234 -0
- package/rules/security/S038_no_version_headers/analyzer.js +262 -0
- package/rules/security/S038_no_version_headers/config.json +49 -0
- package/rules/security/S038_no_version_headers/regex-based-analyzer.js +339 -0
- package/rules/security/S038_no_version_headers/symbol-based-analyzer.js +375 -0
- package/rules/security/S039_no_session_tokens_in_url/README.md +198 -0
- package/rules/security/S039_no_session_tokens_in_url/analyzer.js +262 -0
- package/rules/security/S039_no_session_tokens_in_url/config.json +92 -0
- package/rules/security/S039_no_session_tokens_in_url/regex-based-analyzer.js +337 -0
- package/rules/security/S039_no_session_tokens_in_url/symbol-based-analyzer.js +436 -0
- package/rules/security/S049_short_validity_tokens/analyzer.js +175 -0
- package/rules/security/S049_short_validity_tokens/config.json +124 -0
- package/rules/security/S049_short_validity_tokens/regex-based-analyzer.js +295 -0
- package/rules/security/S049_short_validity_tokens/symbol-based-analyzer.js +389 -0
- package/rules/security/S051_password_length_policy/analyzer.js +410 -0
- package/rules/security/S051_password_length_policy/config.json +83 -0
- package/rules/security/S052_weak_otp_entropy/analyzer.js +403 -0
- package/rules/security/S052_weak_otp_entropy/config.json +57 -0
- package/rules/security/S054_no_default_accounts/README.md +129 -0
- package/rules/security/S054_no_default_accounts/analyzer.js +792 -0
- package/rules/security/S054_no_default_accounts/config.json +101 -0
- package/rules/security/S056_log_injection_protection/analyzer.js +242 -0
- package/rules/security/S056_log_injection_protection/config.json +148 -0
- package/rules/security/S056_log_injection_protection/regex-based-analyzer.js +120 -0
- package/rules/security/S056_log_injection_protection/symbol-based-analyzer.js +287 -0
- package/rules/security/S057_utc_logging/README.md +152 -0
- package/rules/security/S057_utc_logging/analyzer.js +457 -0
- package/rules/security/S057_utc_logging/config.json +105 -0
- package/rules/security/S058_no_ssrf/README.md +180 -0
- package/rules/security/S058_no_ssrf/analyzer.js +403 -0
- package/rules/security/S058_no_ssrf/config.json +125 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,82 @@
|
|
|
2
2
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## ๐งช **v1.3.8 - C065 Rule Enhancement & Advanced Context Analysis (October 1, 2025)**
|
|
6
|
+
|
|
7
|
+
**Release Date**: October 1, 2025
|
|
8
|
+
**Type**: Major Enhancement
|
|
9
|
+
**Branch**: `feature.sunlint.heuristic_rule_c065`
|
|
10
|
+
|
|
11
|
+
### โจ **Major Features**
|
|
12
|
+
- **ENHANCED**: C065 "One Behavior per Test" Rule with Advanced Context Analysis
|
|
13
|
+
- **New**: UI Workflow Detection for legitimate testing patterns
|
|
14
|
+
- **New**: UI Interaction Loop Detection (fireEvent iterations)
|
|
15
|
+
- **New**: Smart Control Flow Analysis with UI pattern exclusions
|
|
16
|
+
- **New**: Assertion context grouping for accurate behavior detection
|
|
17
|
+
- **ENHANCED**: File Targeting System with Smart Test Detection
|
|
18
|
+
- **Performance**: 98% file reduction (6873 โ 112 files) with `--include-tests`
|
|
19
|
+
- **Accuracy**: Intelligent project targeting and language filter override
|
|
20
|
+
- **ENHANCED**: Debug Output Management
|
|
21
|
+
- **Clean**: Production-ready output with conditional debug logging
|
|
22
|
+
- **Detailed**: Comprehensive debug info available with `--verbose` flag
|
|
23
|
+
|
|
24
|
+
### ๐ **Critical Bug Fixes**
|
|
25
|
+
- **FIXED**: C065 Rule Registry and Configuration
|
|
26
|
+
- **Issue**: Rule loading from incorrect `rules/quality/` path
|
|
27
|
+
- **Solution**: Updated to correct `rules/common/` path with proper categorization
|
|
28
|
+
- **FIXED**: False Positive Control Flow Detection
|
|
29
|
+
- **Issue**: UI testing loops incorrectly flagged as violations
|
|
30
|
+
- **Solution**: Pattern recognition for legitimate UI element iteration
|
|
31
|
+
- **FIXED**: Test File Language Filtering
|
|
32
|
+
- **Issue**: Test files excluded by language patterns
|
|
33
|
+
- **Solution**: Override exclusions for `--include-tests` flag
|
|
34
|
+
|
|
35
|
+
### ๐ฏ **Rule Accuracy Validation**
|
|
36
|
+
- **UI Loops**: `for (const checkbox of listCheckbox) { fireEvent.click(checkbox); }` โ
No false positive
|
|
37
|
+
- **Button Iteration**: `for (const button of buttons) { fireEvent.click(button); }` โ
No false positive
|
|
38
|
+
- **Business Logic**: Complex control flow with if/else statements โ Properly flagged
|
|
39
|
+
- **Multiple Behaviors**: Tests with multiple mock setups โ Properly flagged
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## ๏ฟฝ **v1.3.7 - File Count Reporting & Performance Fixes (September 11, 2025)**
|
|
44
|
+
|
|
45
|
+
**Release Date**: September 11, 2025
|
|
46
|
+
**Type**: Bug Fix & Enhancement
|
|
47
|
+
**Branch**: `fix.sunlint.report`
|
|
48
|
+
|
|
49
|
+
### ๐ **Critical Bug Fixes**
|
|
50
|
+
- **FIXED**: File count reporting accuracy in summary
|
|
51
|
+
- **Issue**: Summary showed incorrect file counts when performance filtering applied
|
|
52
|
+
- **Before**: `Files loaded: 1322` but summary `Files: 1000` (misleading)
|
|
53
|
+
- **After**: Summary accurately reflects files actually analyzed
|
|
54
|
+
- **FIXED**: File count multiplication in batch processing
|
|
55
|
+
- **Issue**: Multiple batches incorrectly accumulated file counts
|
|
56
|
+
- **Before**: 1322 files โ reported as 3000 files in batched analysis
|
|
57
|
+
- **After**: Consistent file count regardless of batch strategy
|
|
58
|
+
|
|
59
|
+
### โก **Performance Enhancements**
|
|
60
|
+
- **ENHANCED**: `--max-files=-1` unlimited file processing
|
|
61
|
+
- **Issue**: `-1` flag was ignored, still limited to 1000 files
|
|
62
|
+
- **Solution**: Proper unlimited file processing support
|
|
63
|
+
- **Usage**: `sunlint --max-files=-1` now analyzes all files without limits
|
|
64
|
+
|
|
65
|
+
### ๐ฏ **Rule Improvements**
|
|
66
|
+
- **ENHANCED**: S057 UTC Logging rule precision (100% accuracy)
|
|
67
|
+
- Fixed false positive detection for `pino.stdTimeFunctions.isoTime`
|
|
68
|
+
- Added timezone indicator support: `'Z'`, `"Z"`, `+00:00`, `.l'Z'`
|
|
69
|
+
- Enhanced config variable tracing for complex logging setups
|
|
70
|
+
- Cleaned up test fixtures and moved to proper location
|
|
71
|
+
|
|
72
|
+
### ๐ **Validation Results**
|
|
73
|
+
- **File Processing**: `--max-files=-1` โ 1322 files analyzed โ
|
|
74
|
+
- **Limited Analysis**: `--max-files=500` โ 500 files analyzed โ
|
|
75
|
+
- **Batch Analysis**: Multi-rule analysis maintains accurate counts โ
|
|
76
|
+
- **S057 Precision**: 0 false positives on real projects โ
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## ๏ฟฝ๐ง **v1.3.6 - C067 False Positive Reduction (September 8, 2025)**
|
|
6
81
|
|
|
7
82
|
**Release Date**: September 8, 2025
|
|
8
83
|
**Type**: Bug Fix & Improvement
|
|
@@ -41,6 +41,26 @@ module.exports = {
|
|
|
41
41
|
reason: 'JSON injection detection requires AST context analysis',
|
|
42
42
|
methods: ['ast', 'regex'],
|
|
43
43
|
accuracy: { ast: 95, regex: 60 }
|
|
44
|
+
},
|
|
45
|
+
'S054': {
|
|
46
|
+
reason: 'Default account detection in code, SQL, and config files',
|
|
47
|
+
methods: ['regex', 'ast'],
|
|
48
|
+
accuracy: { regex: 85, ast: 90 }
|
|
49
|
+
},
|
|
50
|
+
'S052': {
|
|
51
|
+
reason: 'OTP entropy analysis requires hybrid approach for RNG detection and context awareness',
|
|
52
|
+
methods: ['regex', 'ast'],
|
|
53
|
+
accuracy: { regex: 80, ast: 90 }
|
|
54
|
+
},
|
|
55
|
+
'S051': {
|
|
56
|
+
reason: 'Password length policy requires multi-signal context detection and cross-file validation',
|
|
57
|
+
methods: ['regex', 'ast'],
|
|
58
|
+
accuracy: { regex: 85, ast: 92 }
|
|
59
|
+
},
|
|
60
|
+
'C065': {
|
|
61
|
+
reason: 'Test behavior analysis requires hybrid heuristic + AST context for multiple assertions and control flow detection',
|
|
62
|
+
methods: ['regex', 'ast'],
|
|
63
|
+
accuracy: { regex: 85, ast: 92 }
|
|
44
64
|
}
|
|
45
65
|
},
|
|
46
66
|
|
|
@@ -736,7 +736,13 @@
|
|
|
736
736
|
"config": "./rules/security/S025_server_side_validation/config.json",
|
|
737
737
|
"version": "1.0.0",
|
|
738
738
|
"status": "stable",
|
|
739
|
-
"tags": [
|
|
739
|
+
"tags": [
|
|
740
|
+
"security",
|
|
741
|
+
"validation",
|
|
742
|
+
"server-side",
|
|
743
|
+
"owasp",
|
|
744
|
+
"input-validation"
|
|
745
|
+
],
|
|
740
746
|
"strategy": {
|
|
741
747
|
"preferred": "ast",
|
|
742
748
|
"fallbacks": ["ast", "regex"],
|
|
@@ -927,40 +933,71 @@
|
|
|
927
933
|
"tags": ["security", "file-inclusion", "path-traversal"]
|
|
928
934
|
},
|
|
929
935
|
"S037": {
|
|
930
|
-
"name": "
|
|
931
|
-
"description": "
|
|
936
|
+
"name": "Configure comprehensive cache headers to prevent sensitive data leakage",
|
|
937
|
+
"description": "Configure comprehensive cache headers (Cache-Control: no-store, no-cache, must-revalidate, Pragma: no-cache, Expires: 0) for sensitive responses to avoid caching sensitive data in browsers or intermediaries.",
|
|
932
938
|
"category": "security",
|
|
933
939
|
"severity": "warning",
|
|
934
940
|
"languages": ["typescript", "javascript"],
|
|
935
|
-
"analyzer": "
|
|
936
|
-
"
|
|
941
|
+
"analyzer": "./rules/security/S037_cache_headers/analyzer.js",
|
|
942
|
+
"config": "./rules/security/S037_cache_headers/config.json",
|
|
937
943
|
"version": "1.0.0",
|
|
938
|
-
"status": "
|
|
939
|
-
"tags": ["security", "caching", "headers"]
|
|
944
|
+
"status": "experimental",
|
|
945
|
+
"tags": ["security", "caching", "headers", "privacy"],
|
|
946
|
+
"strategy": {
|
|
947
|
+
"preferred": "ast",
|
|
948
|
+
"fallbacks": ["ast", "regex"],
|
|
949
|
+
"accuracy": { "ast": 90, "regex": 75 }
|
|
950
|
+
},
|
|
951
|
+
"engineMappings": {
|
|
952
|
+
"heuristic": ["rules/security/S037_cache_headers/analyzer.js"]
|
|
953
|
+
}
|
|
940
954
|
},
|
|
941
955
|
"S038": {
|
|
942
|
-
"name": "
|
|
943
|
-
"description": "Prevent version information disclosure",
|
|
956
|
+
"name": "Do not expose version information in response headers",
|
|
957
|
+
"description": "Prevent exposure of server version information through response headers (Server, X-Powered-By, X-AspNet-Version, etc.) to reduce information disclosure and potential attack vectors.",
|
|
944
958
|
"category": "security",
|
|
945
959
|
"severity": "warning",
|
|
946
960
|
"languages": ["typescript", "javascript"],
|
|
947
|
-
"analyzer": "
|
|
948
|
-
"
|
|
961
|
+
"analyzer": "./rules/security/S038_no_version_headers/analyzer.js",
|
|
962
|
+
"config": "./rules/security/S038_no_version_headers/config.json",
|
|
949
963
|
"version": "1.0.0",
|
|
950
|
-
"status": "
|
|
951
|
-
"tags": ["security", "information-disclosure", "version"]
|
|
964
|
+
"status": "experimental",
|
|
965
|
+
"tags": ["security", "information-disclosure", "version", "headers"],
|
|
966
|
+
"strategy": {
|
|
967
|
+
"preferred": "ast",
|
|
968
|
+
"fallbacks": ["ast", "regex"],
|
|
969
|
+
"accuracy": { "ast": 90, "regex": 75 }
|
|
970
|
+
},
|
|
971
|
+
"engineMappings": {
|
|
972
|
+
"heuristic": ["rules/security/S038_no_version_headers/analyzer.js"]
|
|
973
|
+
}
|
|
952
974
|
},
|
|
953
975
|
"S039": {
|
|
954
|
-
"name": "
|
|
955
|
-
"description": "
|
|
976
|
+
"name": "Do not pass Session Tokens via URL parameters",
|
|
977
|
+
"description": "Detects when session tokens, authentication tokens, JWT tokens, or other sensitive authentication data are passed as URL parameters instead of secure headers or request body. URL parameters are logged in web server logs, browser history, and can be exposed in referrer headers.",
|
|
956
978
|
"category": "security",
|
|
957
|
-
"severity": "
|
|
979
|
+
"severity": "warning",
|
|
958
980
|
"languages": ["typescript", "javascript"],
|
|
959
|
-
"analyzer": "
|
|
960
|
-
"
|
|
981
|
+
"analyzer": "./rules/security/S039_no_session_tokens_in_url/analyzer.js",
|
|
982
|
+
"config": "./rules/security/S039_no_session_tokens_in_url/config.json",
|
|
961
983
|
"version": "1.0.0",
|
|
962
|
-
"status": "
|
|
963
|
-
"tags": [
|
|
984
|
+
"status": "experimental",
|
|
985
|
+
"tags": [
|
|
986
|
+
"security",
|
|
987
|
+
"session-tokens",
|
|
988
|
+
"url-parameters",
|
|
989
|
+
"authentication"
|
|
990
|
+
],
|
|
991
|
+
"strategy": {
|
|
992
|
+
"preferred": "ast",
|
|
993
|
+
"fallbacks": ["ast", "regex"],
|
|
994
|
+
"accuracy": { "ast": 85, "regex": 70 }
|
|
995
|
+
},
|
|
996
|
+
"engineMappings": {
|
|
997
|
+
"heuristic": [
|
|
998
|
+
"rules/security/S039_no_session_tokens_in_url/analyzer.js"
|
|
999
|
+
]
|
|
1000
|
+
}
|
|
964
1001
|
},
|
|
965
1002
|
"S041": {
|
|
966
1003
|
"name": "Require Session Invalidate on Logout",
|
|
@@ -1058,6 +1095,36 @@
|
|
|
1058
1095
|
"status": "stable",
|
|
1059
1096
|
"tags": ["security", "password", "recovery"]
|
|
1060
1097
|
},
|
|
1098
|
+
"S049": {
|
|
1099
|
+
"name": "Authentication tokens should have short validity periods",
|
|
1100
|
+
"description": "Authentication tokens (JWT, session tokens, etc.) should have appropriately short validity periods to minimize the risk of token compromise. Long-lived tokens increase the attack surface and potential impact of token theft.",
|
|
1101
|
+
"category": "security",
|
|
1102
|
+
"severity": "error",
|
|
1103
|
+
"languages": ["typescript", "javascript"],
|
|
1104
|
+
"analyzer": "./rules/security/S049_short_validity_tokens/analyzer.js",
|
|
1105
|
+
"config": "./rules/security/S049_short_validity_tokens/config.json",
|
|
1106
|
+
"version": "1.0.0",
|
|
1107
|
+
"status": "stable",
|
|
1108
|
+
"tags": [
|
|
1109
|
+
"security",
|
|
1110
|
+
"authentication",
|
|
1111
|
+
"tokens",
|
|
1112
|
+
"jwt",
|
|
1113
|
+
"session",
|
|
1114
|
+
"owasp"
|
|
1115
|
+
],
|
|
1116
|
+
"strategy": {
|
|
1117
|
+
"preferred": "ast",
|
|
1118
|
+
"fallbacks": ["ast", "regex"],
|
|
1119
|
+
"accuracy": {
|
|
1120
|
+
"ast": 90,
|
|
1121
|
+
"regex": 75
|
|
1122
|
+
}
|
|
1123
|
+
},
|
|
1124
|
+
"engineMappings": {
|
|
1125
|
+
"heuristic": ["rules/security/S049_short_validity_tokens/analyzer.js"]
|
|
1126
|
+
}
|
|
1127
|
+
},
|
|
1061
1128
|
"S050": {
|
|
1062
1129
|
"name": "Session Token Weak Hash",
|
|
1063
1130
|
"description": "Prevent weak hashing for session tokens",
|
|
@@ -1070,29 +1137,71 @@
|
|
|
1070
1137
|
"status": "stable",
|
|
1071
1138
|
"tags": ["security", "session", "hashing"]
|
|
1072
1139
|
},
|
|
1140
|
+
"S051": {
|
|
1141
|
+
"name": "Password length policy enforcement (12-64 chars recommended, reject >128)",
|
|
1142
|
+
"description": "Enforce strong password length policies with multi-signal detection. Prevent weak validators, missing limits, and FE/BE mismatches.",
|
|
1143
|
+
"category": "security",
|
|
1144
|
+
"severity": "error",
|
|
1145
|
+
"languages": ["typescript", "javascript"],
|
|
1146
|
+
"analyzer": "./rules/security/S051_password_length_policy/analyzer.js",
|
|
1147
|
+
"config": "./rules/security/S051_password_length_policy/config.json",
|
|
1148
|
+
"eslintRule": "custom/typescript_s051",
|
|
1149
|
+
"version": "1.0.0",
|
|
1150
|
+
"status": "stable",
|
|
1151
|
+
"tags": ["security", "password", "validation", "length", "policy"],
|
|
1152
|
+
"engineMappings": {
|
|
1153
|
+
"eslint": ["custom/typescript_s051"],
|
|
1154
|
+
"heuristic": ["./rules/security/S051_password_length_policy/analyzer.js"]
|
|
1155
|
+
}
|
|
1156
|
+
},
|
|
1157
|
+
"C065": {
|
|
1158
|
+
"name": "One Behavior per Test (AAA Pattern)",
|
|
1159
|
+
"description": "Enforce single behavior testing - each test should verify exactly one action/behavior with clear Arrange-Act-Assert structure",
|
|
1160
|
+
"category": "common",
|
|
1161
|
+
"severity": "warning",
|
|
1162
|
+
"languages": ["typescript", "javascript", "java", "csharp", "swift", "kotlin", "python"],
|
|
1163
|
+
"analyzer": "./rules/common/C065_one_behavior_per_test/analyzer.js",
|
|
1164
|
+
"config": "./rules/common/C065_one_behavior_per_test/config.json",
|
|
1165
|
+
"version": "1.0.0",
|
|
1166
|
+
"status": "stable",
|
|
1167
|
+
"tags": ["testing", "aaa", "behavior", "maintainability", "clarity"],
|
|
1168
|
+
"engineMappings": {
|
|
1169
|
+
"heuristic": ["./rules/common/C065_one_behavior_per_test/analyzer.js"]
|
|
1170
|
+
}
|
|
1171
|
+
},
|
|
1073
1172
|
"S052": {
|
|
1074
|
-
"name": "
|
|
1075
|
-
"description": "
|
|
1173
|
+
"name": "OTP must have โฅ20-bit entropy (โฅ6 digits) and use CSPRNG",
|
|
1174
|
+
"description": "Prevent guessable OTP by enforcing CSPRNG and minimal entropy. Ban non-crypto RNG and too-short codes.",
|
|
1076
1175
|
"category": "security",
|
|
1077
1176
|
"severity": "error",
|
|
1078
1177
|
"languages": ["typescript", "javascript"],
|
|
1079
|
-
"analyzer": "
|
|
1178
|
+
"analyzer": "./rules/security/S052_weak_otp_entropy/analyzer.js",
|
|
1179
|
+
"config": "./rules/security/S052_weak_otp_entropy/config.json",
|
|
1080
1180
|
"eslintRule": "custom/typescript_s052",
|
|
1081
1181
|
"version": "1.0.0",
|
|
1082
1182
|
"status": "stable",
|
|
1083
|
-
"tags": ["security", "
|
|
1183
|
+
"tags": ["security", "otp", "entropy", "csprng"],
|
|
1184
|
+
"engines": {
|
|
1185
|
+
"eslint": ["custom/typescript_s052"],
|
|
1186
|
+
"heuristic": ["./rules/security/S052_weak_otp_entropy/analyzer.js"]
|
|
1187
|
+
}
|
|
1084
1188
|
},
|
|
1085
1189
|
"S054": {
|
|
1086
|
-
"name": "
|
|
1087
|
-
"description": "
|
|
1190
|
+
"name": "Disallow Default/Built-in Accounts (admin/root/sa/...)",
|
|
1191
|
+
"description": "Prevent use of default or shared accounts. Enforce per-user identities, initial password change, and disabling well-known built-ins.",
|
|
1088
1192
|
"category": "security",
|
|
1089
1193
|
"severity": "error",
|
|
1090
|
-
"languages": ["typescript", "javascript"],
|
|
1091
|
-
"analyzer": "
|
|
1194
|
+
"languages": ["typescript", "javascript", "sql", "terraform", "yaml", "dockerfile", "all"],
|
|
1195
|
+
"analyzer": "./rules/security/S054_no_default_accounts/analyzer.js",
|
|
1196
|
+
"config": "./rules/security/S054_no_default_accounts/config.json",
|
|
1092
1197
|
"eslintRule": "custom/typescript_s054",
|
|
1093
1198
|
"version": "1.0.0",
|
|
1094
1199
|
"status": "stable",
|
|
1095
|
-
"tags": ["security", "accounts", "default"]
|
|
1200
|
+
"tags": ["security", "accounts", "default", "authentication", "authorization"],
|
|
1201
|
+
"engines": {
|
|
1202
|
+
"eslint": ["custom/typescript_s054"],
|
|
1203
|
+
"heuristic": ["./rules/security/S054_no_default_accounts/analyzer.js"]
|
|
1204
|
+
}
|
|
1096
1205
|
},
|
|
1097
1206
|
"S055": {
|
|
1098
1207
|
"name": "REST Content-Type Verification",
|
|
@@ -1106,29 +1215,62 @@
|
|
|
1106
1215
|
"status": "stable",
|
|
1107
1216
|
"tags": ["security", "rest", "content-type"]
|
|
1108
1217
|
},
|
|
1218
|
+
"S056": {
|
|
1219
|
+
"name": "Protect against Log Injection attacks",
|
|
1220
|
+
"description": "Protect against Log Injection attacks. Log injection occurs when user-controlled data is written to log files without proper sanitization, potentially allowing attackers to manipulate log entries, inject malicious content, or exploit log processing systems.",
|
|
1221
|
+
"category": "security",
|
|
1222
|
+
"severity": "error",
|
|
1223
|
+
"languages": ["typescript", "javascript"],
|
|
1224
|
+
"analyzer": "./rules/security/S056_log_injection_protection/analyzer.js",
|
|
1225
|
+
"config": "./rules/security/S056_log_injection_protection/config.json",
|
|
1226
|
+
"version": "1.0.0",
|
|
1227
|
+
"status": "stable",
|
|
1228
|
+
"tags": ["security", "logging", "injection", "owasp", "crlf"],
|
|
1229
|
+
"strategy": {
|
|
1230
|
+
"preferred": "ast",
|
|
1231
|
+
"fallbacks": ["ast", "regex"],
|
|
1232
|
+
"accuracy": {
|
|
1233
|
+
"ast": 95,
|
|
1234
|
+
"regex": 85
|
|
1235
|
+
}
|
|
1236
|
+
},
|
|
1237
|
+
"engineMappings": {
|
|
1238
|
+
"heuristic": [
|
|
1239
|
+
"rules/security/S056_log_injection_protection/analyzer.js"
|
|
1240
|
+
]
|
|
1241
|
+
}
|
|
1242
|
+
},
|
|
1109
1243
|
"S057": {
|
|
1110
|
-
"name": "UTC
|
|
1111
|
-
"description": "
|
|
1244
|
+
"name": "Log with UTC Timestamps",
|
|
1245
|
+
"description": "Ensure all logs use synchronized UTC time with ISO 8601/RFC3339 format to avoid timezone discrepancies across systems",
|
|
1112
1246
|
"category": "security",
|
|
1113
1247
|
"severity": "warning",
|
|
1114
1248
|
"languages": ["typescript", "javascript"],
|
|
1115
|
-
"analyzer": "
|
|
1116
|
-
"
|
|
1249
|
+
"analyzer": "./rules/security/S057_utc_logging/analyzer.js",
|
|
1250
|
+
"config": "./rules/security/S057_utc_logging/config.json",
|
|
1117
1251
|
"version": "1.0.0",
|
|
1118
1252
|
"status": "stable",
|
|
1119
|
-
"tags": ["security", "logging", "timezone"]
|
|
1253
|
+
"tags": ["security", "logging", "timezone", "utc"],
|
|
1254
|
+
"engineMappings": {
|
|
1255
|
+
"eslint": ["custom/typescript_s057"],
|
|
1256
|
+
"heuristic": ["./rules/security/S057_utc_logging/analyzer.js"]
|
|
1257
|
+
}
|
|
1120
1258
|
},
|
|
1121
1259
|
"S058": {
|
|
1122
|
-
"name": "No SSRF",
|
|
1123
|
-
"description": "
|
|
1260
|
+
"name": "No SSRF (Server-Side Request Forgery)",
|
|
1261
|
+
"description": "Prevent SSRF attacks by validating URLs from user input before making HTTP requests",
|
|
1124
1262
|
"category": "security",
|
|
1125
1263
|
"severity": "error",
|
|
1126
1264
|
"languages": ["typescript", "javascript"],
|
|
1127
|
-
"analyzer": "
|
|
1128
|
-
"
|
|
1265
|
+
"analyzer": "./rules/security/S058_no_ssrf/analyzer.js",
|
|
1266
|
+
"config": "./rules/security/S058_no_ssrf/config.json",
|
|
1129
1267
|
"version": "1.0.0",
|
|
1130
1268
|
"status": "stable",
|
|
1131
|
-
"tags": ["security", "ssrf", "url-validation"]
|
|
1269
|
+
"tags": ["security", "ssrf", "url-validation", "http-requests"],
|
|
1270
|
+
"engineMappings": {
|
|
1271
|
+
"heuristic": ["./rules/security/S058_no_ssrf/analyzer.js"],
|
|
1272
|
+
"eslint": ["custom/typescript_s058"]
|
|
1273
|
+
}
|
|
1132
1274
|
},
|
|
1133
1275
|
"C002": {
|
|
1134
1276
|
"id": "C002",
|
|
@@ -1345,7 +1487,13 @@
|
|
|
1345
1487
|
"config": "./rules/common/C067_no_hardcoded_config/config.json",
|
|
1346
1488
|
"version": "1.0.0",
|
|
1347
1489
|
"status": "stable",
|
|
1348
|
-
"tags": [
|
|
1490
|
+
"tags": [
|
|
1491
|
+
"configuration",
|
|
1492
|
+
"hardcode",
|
|
1493
|
+
"environment",
|
|
1494
|
+
"maintainability",
|
|
1495
|
+
"security"
|
|
1496
|
+
],
|
|
1349
1497
|
"strategy": {
|
|
1350
1498
|
"preferred": "ast",
|
|
1351
1499
|
"fallbacks": ["ast"],
|
|
@@ -1367,7 +1515,13 @@
|
|
|
1367
1515
|
"config": "../rules/common/C070_no_real_time_tests/config.json",
|
|
1368
1516
|
"version": "1.0.0",
|
|
1369
1517
|
"status": "stable",
|
|
1370
|
-
"tags": [
|
|
1518
|
+
"tags": [
|
|
1519
|
+
"testing",
|
|
1520
|
+
"flaky-tests",
|
|
1521
|
+
"timing",
|
|
1522
|
+
"fake-timers",
|
|
1523
|
+
"reliability"
|
|
1524
|
+
],
|
|
1371
1525
|
"strategy": {
|
|
1372
1526
|
"preferred": "ast",
|
|
1373
1527
|
"fallbacks": ["regex"],
|
|
@@ -1377,7 +1531,9 @@
|
|
|
1377
1531
|
}
|
|
1378
1532
|
},
|
|
1379
1533
|
"engineMappings": {
|
|
1380
|
-
"heuristic": [
|
|
1534
|
+
"heuristic": [
|
|
1535
|
+
"../rules/common/C070_no_real_time_tests/regex-analyzer.js"
|
|
1536
|
+
]
|
|
1381
1537
|
}
|
|
1382
1538
|
},
|
|
1383
1539
|
"C072": {
|
|
@@ -1400,6 +1556,33 @@
|
|
|
1400
1556
|
"accuracy": {}
|
|
1401
1557
|
}
|
|
1402
1558
|
},
|
|
1559
|
+
"C073": {
|
|
1560
|
+
"id": "C073",
|
|
1561
|
+
"name": "Validate Required Configuration on Startup",
|
|
1562
|
+
"description": "C073 - Validate mandatory configuration at startup and fail fast on invalid/missing values",
|
|
1563
|
+
"category": "configuration",
|
|
1564
|
+
"severity": "error",
|
|
1565
|
+
"languages": ["typescript", "javascript", "java", "go"],
|
|
1566
|
+
"version": "1.0.0",
|
|
1567
|
+
"status": "stable",
|
|
1568
|
+
"tags": ["configuration", "validation", "startup", "fail-fast"],
|
|
1569
|
+
"engineMappings": {
|
|
1570
|
+
"heuristic": [
|
|
1571
|
+
"rules/common/C073_validate_required_config_on_startup/analyzer.js"
|
|
1572
|
+
],
|
|
1573
|
+
"semantic": [
|
|
1574
|
+
"rules/common/C073_validate_required_config_on_startup/symbol-based-analyzer.js"
|
|
1575
|
+
]
|
|
1576
|
+
},
|
|
1577
|
+
"strategy": {
|
|
1578
|
+
"preferred": "semantic",
|
|
1579
|
+
"fallbacks": ["heuristic"],
|
|
1580
|
+
"accuracy": {
|
|
1581
|
+
"semantic": 0.9,
|
|
1582
|
+
"heuristic": 0.7
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
},
|
|
1403
1586
|
"C075": {
|
|
1404
1587
|
"id": "C075",
|
|
1405
1588
|
"name": "Rule C075",
|
|
@@ -1806,7 +1989,9 @@
|
|
|
1806
1989
|
"C047",
|
|
1807
1990
|
"C048",
|
|
1808
1991
|
"C052",
|
|
1992
|
+
"C065",
|
|
1809
1993
|
"C072",
|
|
1994
|
+
"C073",
|
|
1810
1995
|
"C075",
|
|
1811
1996
|
"T002",
|
|
1812
1997
|
"T003",
|
|
@@ -1874,9 +2059,11 @@
|
|
|
1874
2059
|
"S047",
|
|
1875
2060
|
"S048",
|
|
1876
2061
|
"S050",
|
|
2062
|
+
"S051",
|
|
1877
2063
|
"S052",
|
|
1878
2064
|
"S054",
|
|
1879
2065
|
"S055",
|
|
2066
|
+
"S056",
|
|
1880
2067
|
"S057",
|
|
1881
2068
|
"S058"
|
|
1882
2069
|
],
|
|
@@ -1971,7 +2158,7 @@
|
|
|
1971
2158
|
"lastUpdated": "2025-08-25",
|
|
1972
2159
|
"totalRules": 98,
|
|
1973
2160
|
"qualityRules": 33,
|
|
1974
|
-
"securityRules":
|
|
2161
|
+
"securityRules": 51,
|
|
1975
2162
|
"stableRules": 45,
|
|
1976
2163
|
"experimentalRules": 1,
|
|
1977
2164
|
"supportedLanguages": 4,
|
|
@@ -264,7 +264,7 @@ class AnalysisOrchestrator {
|
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
// Merge results and add performance metrics
|
|
267
|
-
const mergedResults = this.mergeEngineResults(results, options);
|
|
267
|
+
const mergedResults = this.mergeEngineResults(results, options, optimizedFiles.length);
|
|
268
268
|
mergedResults.performance = performanceMetrics;
|
|
269
269
|
|
|
270
270
|
return mergedResults;
|
|
@@ -523,7 +523,7 @@ class AnalysisOrchestrator {
|
|
|
523
523
|
* @param {Object} options - Analysis options
|
|
524
524
|
* @returns {Object} Merged results
|
|
525
525
|
*/
|
|
526
|
-
mergeEngineResults(engineResults, options) {
|
|
526
|
+
mergeEngineResults(engineResults, options, actualFilesCount = 0) {
|
|
527
527
|
const mergedResults = {
|
|
528
528
|
results: [],
|
|
529
529
|
summary: {
|
|
@@ -568,15 +568,19 @@ class AnalysisOrchestrator {
|
|
|
568
568
|
// Accumulate engine statistics across batches
|
|
569
569
|
mergedResults.summary.engines[engineName].rules.push(...(engineResult.rules || []));
|
|
570
570
|
mergedResults.summary.engines[engineName].violations += violationCount;
|
|
571
|
-
|
|
571
|
+
// Don't accumulate filesAnalyzed for each batch - use actual unique file count
|
|
572
|
+
if (!mergedResults.summary.engines[engineName].filesSet) {
|
|
573
|
+
mergedResults.summary.engines[engineName].files = actualFilesCount;
|
|
574
|
+
mergedResults.summary.engines[engineName].filesSet = true;
|
|
575
|
+
}
|
|
572
576
|
mergedResults.summary.engines[engineName].batches += 1;
|
|
573
577
|
|
|
574
578
|
mergedResults.summary.totalViolations += violationCount;
|
|
575
|
-
mergedResults.summary.totalFiles += engineResult.filesAnalyzed || 0;
|
|
576
579
|
}
|
|
577
580
|
|
|
578
|
-
// Update unique engine count
|
|
581
|
+
// Update unique engine count and correct total files count
|
|
579
582
|
mergedResults.summary.totalEngines = uniqueEngines.size;
|
|
583
|
+
mergedResults.summary.totalFiles = actualFilesCount;
|
|
580
584
|
|
|
581
585
|
return mergedResults;
|
|
582
586
|
}
|