@sun-asterisk/sunlint 1.3.0 → 1.3.2
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 +115 -1
- package/CONTRIBUTING.md +249 -605
- package/README.md +3 -4
- package/config/ci-cd.json +54 -0
- package/config/development.json +56 -0
- package/config/large-project.json +143 -0
- package/config/presets/all.json +0 -1
- package/config/release.json +70 -0
- package/config/rule-analysis-strategies.js +38 -3
- package/config/rules/enhanced-rules-registry.json +474 -1179
- package/config/rules/rules-registry-generated.json +3 -3
- package/core/cli-action-handler.js +24 -30
- package/core/cli-program.js +11 -3
- package/core/config-merger.js +29 -2
- package/core/enhanced-rules-registry.js +3 -2
- package/core/semantic-engine.js +129 -19
- package/core/semantic-rule-base.js +4 -2
- package/core/unified-rule-registry.js +1 -1
- package/docs/COMMAND-EXAMPLES.md +134 -0
- package/docs/LARGE-PROJECT-GUIDE.md +324 -0
- package/engines/heuristic-engine.js +135 -16
- package/integrations/eslint/plugin/index.js +0 -2
- package/integrations/eslint/plugin/rules/common/c003-no-vague-abbreviations.js +59 -1
- package/integrations/eslint/plugin/rules/common/c006-function-name-verb-noun.js +26 -1
- package/integrations/eslint/plugin/rules/common/c030-use-custom-error-classes.js +54 -19
- package/origin-rules/common-en.md +19 -15
- package/package.json +1 -1
- package/rules/common/C002_no_duplicate_code/analyzer.js +334 -36
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +220 -35
- package/rules/common/C006_function_naming/analyzer.js +29 -3
- package/rules/common/C010_limit_block_nesting/analyzer.js +181 -337
- package/rules/common/C010_limit_block_nesting/config.json +64 -0
- package/rules/common/C010_limit_block_nesting/regex-based-analyzer.js +379 -0
- package/rules/common/C010_limit_block_nesting/symbol-based-analyzer.js +231 -0
- package/rules/common/C013_no_dead_code/analyzer.js +75 -177
- package/rules/common/C013_no_dead_code/config.json +61 -0
- package/rules/common/C013_no_dead_code/regex-based-analyzer.js +345 -0
- package/rules/common/C013_no_dead_code/symbol-based-analyzer.js +640 -0
- package/rules/common/C014_dependency_injection/analyzer.js +48 -313
- package/rules/common/C014_dependency_injection/config.json +26 -0
- package/rules/common/C014_dependency_injection/symbol-based-analyzer.js +751 -0
- package/rules/common/C017_constructor_logic/analyzer.js +254 -17
- package/rules/common/C017_constructor_logic/semantic-analyzer.js +340 -0
- package/rules/common/C018_no_throw_generic_error/analyzer.js +232 -0
- package/rules/common/C018_no_throw_generic_error/config.json +50 -0
- package/rules/common/C018_no_throw_generic_error/regex-based-analyzer.js +387 -0
- package/rules/common/C018_no_throw_generic_error/symbol-based-analyzer.js +314 -0
- package/rules/common/C019_log_level_usage/analyzer.js +110 -317
- package/rules/common/C019_log_level_usage/pattern-analyzer.js +88 -0
- package/rules/common/C019_log_level_usage/system-log-analyzer.js +1267 -0
- package/rules/common/C023_no_duplicate_variable/analyzer.js +180 -0
- package/rules/common/C023_no_duplicate_variable/config.json +50 -0
- package/rules/common/C023_no_duplicate_variable/symbol-based-analyzer.js +158 -0
- package/rules/common/C024_no_scatter_hardcoded_constants/analyzer.js +180 -0
- package/rules/common/C024_no_scatter_hardcoded_constants/config.json +50 -0
- package/rules/common/C024_no_scatter_hardcoded_constants/symbol-based-analyzer.js +181 -0
- package/rules/common/C030_use_custom_error_classes/analyzer.js +200 -0
- package/rules/common/C033_separate_service_repository/README.md +78 -0
- package/rules/common/C033_separate_service_repository/analyzer.js +160 -0
- package/rules/common/C033_separate_service_repository/config.json +50 -0
- package/rules/common/C033_separate_service_repository/regex-based-analyzer.js +585 -0
- package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +368 -0
- package/rules/common/C035_error_logging_context/STRATEGY.md +99 -0
- package/rules/common/C035_error_logging_context/analyzer.js +232 -0
- package/rules/common/C035_error_logging_context/config.json +54 -0
- package/rules/common/C035_error_logging_context/regex-based-analyzer.js +299 -0
- package/rules/common/C035_error_logging_context/symbol-based-analyzer.js +454 -0
- package/rules/common/C040_centralized_validation/analyzer.js +165 -0
- package/rules/common/C040_centralized_validation/config.json +46 -0
- package/rules/common/C040_centralized_validation/regex-based-analyzer.js +243 -0
- package/rules/common/C040_centralized_validation/symbol-based-analyzer.js +416 -0
- package/rules/common/{C076_single_test_behavior → C072_single_test_behavior}/analyzer.js +6 -6
- package/rules/common/C076_explicit_function_types/README.md +30 -0
- package/rules/common/C076_explicit_function_types/analyzer.js +172 -0
- package/rules/common/C076_explicit_function_types/config.json +15 -0
- package/rules/common/C076_explicit_function_types/semantic-analyzer.js +341 -0
- package/rules/index.js +6 -1
- package/rules/parser/rule-parser.js +13 -2
- package/rules/security/S005_no_origin_auth/README.md +226 -0
- package/rules/security/S005_no_origin_auth/analyzer.js +184 -0
- package/rules/security/S005_no_origin_auth/ast-analyzer.js +406 -0
- package/rules/security/S005_no_origin_auth/config.json +85 -0
- package/rules/security/S006_no_plaintext_recovery_codes/README.md +139 -0
- package/rules/security/S006_no_plaintext_recovery_codes/analyzer.js +306 -0
- package/rules/security/S006_no_plaintext_recovery_codes/config.json +48 -0
- package/rules/security/S007_no_plaintext_otp/README.md +198 -0
- package/rules/security/S007_no_plaintext_otp/analyzer.js +406 -0
- package/rules/security/S007_no_plaintext_otp/config.json +79 -0
- package/rules/security/S007_no_plaintext_otp/semantic-analyzer.js +609 -0
- package/rules/security/S007_no_plaintext_otp/semantic-config.json +195 -0
- package/rules/security/S007_no_plaintext_otp/semantic-wrapper.js +280 -0
- package/rules/security/S009_no_insecure_encryption/README.md +158 -0
- package/rules/security/S009_no_insecure_encryption/analyzer.js +319 -0
- package/rules/security/S009_no_insecure_encryption/config.json +55 -0
- package/rules/security/S010_no_insecure_encryption/README.md +224 -0
- package/rules/security/S010_no_insecure_encryption/analyzer.js +493 -0
- package/rules/security/S010_no_insecure_encryption/config.json +48 -0
- package/rules/security/S016_no_sensitive_querystring/STRATEGY.md +149 -0
- package/rules/security/S016_no_sensitive_querystring/analyzer.js +276 -0
- package/rules/security/S016_no_sensitive_querystring/config.json +127 -0
- package/rules/security/S016_no_sensitive_querystring/regex-based-analyzer.js +258 -0
- package/rules/security/S016_no_sensitive_querystring/symbol-based-analyzer.js +495 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +180 -366
- package/rules/security/S027_no_hardcoded_secrets/categories.json +153 -0
- package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +250 -0
- package/rules/security/S048_no_current_password_in_reset/README.md +222 -0
- package/rules/security/S048_no_current_password_in_reset/analyzer.js +366 -0
- package/rules/security/S048_no_current_password_in_reset/config.json +48 -0
- package/rules/security/S055_content_type_validation/README.md +176 -0
- package/rules/security/S055_content_type_validation/analyzer.js +312 -0
- package/rules/security/S055_content_type_validation/config.json +48 -0
- package/rules/utils/rule-helpers.js +140 -1
- package/scripts/consolidate-config.js +116 -0
- package/scripts/prepare-release.sh +1 -1
- package/config/rules/rules-registry.json +0 -765
- package/docs/ESLINT-INTEGRATION-STRATEGY.md +0 -392
- package/docs/FUTURE_PACKAGES.md +0 -83
- package/docs/HEURISTIC_VS_AI.md +0 -113
- package/docs/PRODUCTION_DEPLOYMENT_ANALYSIS.md +0 -112
- package/docs/PRODUCTION_SIZE_IMPACT.md +0 -183
- package/docs/RELEASE_GUIDE.md +0 -230
- package/docs/STANDARDIZED-CATEGORY-FILTERING.md +0 -156
- package/integrations/eslint/plugin/rules/common/c076-single-behavior-per-test.js +0 -254
- package/rules/common/C006_function_naming/smart-analyzer.js +0 -503
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ruleId": "S007",
|
|
3
|
+
"name": "No Plaintext OTP (Semantic Analysis)",
|
|
4
|
+
"category": "security",
|
|
5
|
+
"severity": "error",
|
|
6
|
+
"type": "semantic",
|
|
7
|
+
"description": "Detects plaintext OTP storage and transmission using semantic analysis with Symbol Table",
|
|
8
|
+
|
|
9
|
+
"analysis": {
|
|
10
|
+
"engine": "semantic",
|
|
11
|
+
"strategy": "symbol-table",
|
|
12
|
+
"crossFileAnalysis": true,
|
|
13
|
+
"requiresTypeChecker": false,
|
|
14
|
+
"cacheResults": true,
|
|
15
|
+
"timeout": 30000,
|
|
16
|
+
"maxFiles": 1000
|
|
17
|
+
},
|
|
18
|
+
|
|
19
|
+
"scope": {
|
|
20
|
+
"fileTypes": [".ts", ".tsx", ".js", ".jsx"],
|
|
21
|
+
"excludePatterns": [
|
|
22
|
+
"**/test/**",
|
|
23
|
+
"**/tests/**",
|
|
24
|
+
"**/__tests__/**",
|
|
25
|
+
"**/*.test.*",
|
|
26
|
+
"**/*.spec.*",
|
|
27
|
+
"**/node_modules/**",
|
|
28
|
+
"**/build/**",
|
|
29
|
+
"**/dist/**"
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
"semanticPatterns": {
|
|
34
|
+
"otpVariables": {
|
|
35
|
+
"patterns": [
|
|
36
|
+
"^(otp|totp|hotp)$",
|
|
37
|
+
"^(one_?time|onetime)_?(password|pass|code)$",
|
|
38
|
+
"^(auth|verification|sms|temp|security|access|login)_?code$",
|
|
39
|
+
"^(two_?factor|2fa|mfa)_?(token|code)$",
|
|
40
|
+
"^pin_?code$"
|
|
41
|
+
],
|
|
42
|
+
"caseInsensitive": true
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
"otpFunctions": {
|
|
46
|
+
"patterns": [
|
|
47
|
+
"^(generate|create|store|save|send|validate|verify)_?otp$",
|
|
48
|
+
"^otp_?(generate|create|store|save|send|validate|verify)$",
|
|
49
|
+
"^(generate|create|store|save|send|validate|verify)_?(auth|verification|sms|temp|security|access|login)_?code$",
|
|
50
|
+
"^send_?(sms|email|auth)_?code$"
|
|
51
|
+
],
|
|
52
|
+
"methodNames": [
|
|
53
|
+
"sendOtp", "storeOtp", "saveOtp", "generateOtp", "verifyOtp",
|
|
54
|
+
"sendSmsCode", "sendAuthCode", "storeAuthCode", "saveAuthCode"
|
|
55
|
+
]
|
|
56
|
+
},
|
|
57
|
+
|
|
58
|
+
"dangerousOperations": {
|
|
59
|
+
"storage": [
|
|
60
|
+
"save", "store", "insert", "update", "create", "persist",
|
|
61
|
+
"collection.insertOne", "collection.updateOne", "db.save",
|
|
62
|
+
"redis.set", "redis.hset", "cache.put", "cache.set"
|
|
63
|
+
],
|
|
64
|
+
"transmission": [
|
|
65
|
+
"send", "emit", "post", "put", "response.json", "res.send",
|
|
66
|
+
"email.send", "sms.send", "notify", "broadcast"
|
|
67
|
+
],
|
|
68
|
+
"browserStorage": [
|
|
69
|
+
"localStorage.setItem", "sessionStorage.setItem",
|
|
70
|
+
"localStorage.set", "sessionStorage.set"
|
|
71
|
+
],
|
|
72
|
+
"logging": [
|
|
73
|
+
"console.log", "console.debug", "console.info",
|
|
74
|
+
"logger.info", "logger.debug", "log.info"
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
|
|
78
|
+
"safeOperations": [
|
|
79
|
+
"bcrypt.hash", "crypto.createHash", "crypto.createHmac",
|
|
80
|
+
"hash", "encrypt", "cipher", "secure", "pbkdf2",
|
|
81
|
+
"scrypt", "argon2", "aes.encrypt", "rsa.encrypt"
|
|
82
|
+
]
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
"violations": {
|
|
86
|
+
"types": {
|
|
87
|
+
"semantic_otp_variable_usage": {
|
|
88
|
+
"severity": "error",
|
|
89
|
+
"message": "OTP variable used in {context} without encryption",
|
|
90
|
+
"suggestion": "Encrypt or hash OTP values before {context}"
|
|
91
|
+
},
|
|
92
|
+
"semantic_otp_function_call": {
|
|
93
|
+
"severity": "warning",
|
|
94
|
+
"message": "Function may handle OTP in plaintext",
|
|
95
|
+
"suggestion": "Ensure OTP values are encrypted before processing"
|
|
96
|
+
},
|
|
97
|
+
"semantic_plaintext_otp_argument": {
|
|
98
|
+
"severity": "error",
|
|
99
|
+
"message": "Potential plaintext OTP passed to {operation}",
|
|
100
|
+
"suggestion": "Encrypt or hash OTP values before storage/transmission"
|
|
101
|
+
},
|
|
102
|
+
"semantic_method_chain_otp": {
|
|
103
|
+
"severity": "error",
|
|
104
|
+
"message": "Method chain exposes OTP in plaintext",
|
|
105
|
+
"suggestion": "Use secure methods for OTP handling in method chains"
|
|
106
|
+
},
|
|
107
|
+
"semantic_data_flow_violation": {
|
|
108
|
+
"severity": "error",
|
|
109
|
+
"message": "OTP flows to unsafe operation without encryption",
|
|
110
|
+
"suggestion": "Ensure OTP is encrypted before reaching this operation"
|
|
111
|
+
},
|
|
112
|
+
"semantic_cross_file_otp_violation": {
|
|
113
|
+
"severity": "warning",
|
|
114
|
+
"message": "Imported OTP symbol used unsafely",
|
|
115
|
+
"suggestion": "Ensure consistent OTP security across file boundaries"
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
"severityMapping": {
|
|
120
|
+
"storage": "error",
|
|
121
|
+
"transmission": "error",
|
|
122
|
+
"browser_storage": "warning",
|
|
123
|
+
"logging": "warning",
|
|
124
|
+
"unknown_dangerous": "info"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
|
|
128
|
+
"dataFlow": {
|
|
129
|
+
"enabled": true,
|
|
130
|
+
"maxDistance": 20,
|
|
131
|
+
"trackAcrossFiles": true,
|
|
132
|
+
"trackThroughCallbacks": true,
|
|
133
|
+
"trackAsyncFlows": true
|
|
134
|
+
},
|
|
135
|
+
|
|
136
|
+
"performance": {
|
|
137
|
+
"symbolTableCaching": true,
|
|
138
|
+
"maxAnalysisDepth": 10,
|
|
139
|
+
"maxCrossFileReferences": 100,
|
|
140
|
+
"timeoutPerFile": 5000
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
"reporting": {
|
|
144
|
+
"includeSymbolContext": true,
|
|
145
|
+
"includeCrossFileReferences": true,
|
|
146
|
+
"includeDataFlowPath": true,
|
|
147
|
+
"includeCodeSnippets": true,
|
|
148
|
+
"confidenceThreshold": 0.7
|
|
149
|
+
},
|
|
150
|
+
|
|
151
|
+
"examples": {
|
|
152
|
+
"violations": [
|
|
153
|
+
{
|
|
154
|
+
"description": "Direct OTP storage",
|
|
155
|
+
"code": "const otp = generateOtp(); await user.save({ otp });",
|
|
156
|
+
"reason": "OTP variable flows directly to storage operation"
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"description": "OTP in response",
|
|
160
|
+
"code": "return response.json({ authCode, success: true });",
|
|
161
|
+
"reason": "OTP variable included in API response"
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
"description": "Method chain violation",
|
|
165
|
+
"code": "this.otpCode.save();",
|
|
166
|
+
"reason": "OTP flows through method chain to unsafe operation"
|
|
167
|
+
}
|
|
168
|
+
],
|
|
169
|
+
|
|
170
|
+
"safePatterns": [
|
|
171
|
+
{
|
|
172
|
+
"description": "Encrypted storage",
|
|
173
|
+
"code": "const hashedOtp = await bcrypt.hash(otp, 10); await user.save({ hashedOtp });",
|
|
174
|
+
"reason": "OTP is hashed before storage"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
"description": "Secure transmission",
|
|
178
|
+
"code": "const encrypted = encrypt(otp, key); await send(encrypted);",
|
|
179
|
+
"reason": "OTP is encrypted before transmission"
|
|
180
|
+
}
|
|
181
|
+
]
|
|
182
|
+
},
|
|
183
|
+
|
|
184
|
+
"metadata": {
|
|
185
|
+
"version": "1.0.0",
|
|
186
|
+
"lastUpdated": "2024-01-20",
|
|
187
|
+
"author": "SunLint Security Team",
|
|
188
|
+
"references": [
|
|
189
|
+
"OWASP A02:2021 - Cryptographic Failures",
|
|
190
|
+
"NIST SP 800-63B - Authentication Guidelines",
|
|
191
|
+
"RFC 6238 - TOTP: Time-Based One-Time Password Algorithm"
|
|
192
|
+
],
|
|
193
|
+
"tags": ["security", "authentication", "otp", "encryption", "semantic"]
|
|
194
|
+
}
|
|
195
|
+
}
|
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S007 Semantic Wrapper
|
|
3
|
+
* Integrates S007SemanticAnalyzer with HeuristicEngine
|
|
4
|
+
* Provides compatibility layer between semantic analysis and existing framework
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const S007SemanticAnalyzer = require('./semantic-analyzer');
|
|
8
|
+
const SemanticRuleBase = require('../../../core/semantic-rule-base');
|
|
9
|
+
|
|
10
|
+
class S007SemanticWrapper extends SemanticRuleBase {
|
|
11
|
+
constructor(options = {}) {
|
|
12
|
+
super('S007', {
|
|
13
|
+
category: 'security',
|
|
14
|
+
severity: 'error',
|
|
15
|
+
description: 'Detects plaintext OTP storage and transmission using semantic analysis',
|
|
16
|
+
crossFileAnalysis: true,
|
|
17
|
+
requiresTypeChecker: false,
|
|
18
|
+
cacheResults: true,
|
|
19
|
+
...options
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
this.semanticAnalyzer = new S007SemanticAnalyzer('S007');
|
|
23
|
+
this.verbose = options.verbose || false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Initialize with semantic engine
|
|
28
|
+
*/
|
|
29
|
+
async initialize(semanticEngine) {
|
|
30
|
+
await super.initialize(semanticEngine);
|
|
31
|
+
|
|
32
|
+
// Initialize the semantic analyzer
|
|
33
|
+
await this.semanticAnalyzer.initialize(semanticEngine);
|
|
34
|
+
|
|
35
|
+
if (this.verbose) {
|
|
36
|
+
console.log(`🧠 S007SemanticWrapper initialized with semantic engine`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Analyze single file using semantic analysis
|
|
42
|
+
*/
|
|
43
|
+
async analyzeFile(filePath, options = {}) {
|
|
44
|
+
if (this.verbose) {
|
|
45
|
+
console.log(`🧠 S007: Analyzing ${filePath} with semantic analysis`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
try {
|
|
49
|
+
// Delegate to semantic analyzer
|
|
50
|
+
await this.semanticAnalyzer.analyzeFile(filePath, options);
|
|
51
|
+
|
|
52
|
+
// Get violations from semantic analyzer
|
|
53
|
+
const semanticViolations = this.semanticAnalyzer.getViolations();
|
|
54
|
+
|
|
55
|
+
// Add violations to our collection
|
|
56
|
+
for (const violation of semanticViolations) {
|
|
57
|
+
this.addViolation(violation);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Clear violations from semantic analyzer for next file
|
|
61
|
+
this.semanticAnalyzer.clearViolations();
|
|
62
|
+
|
|
63
|
+
if (this.verbose && semanticViolations.length > 0) {
|
|
64
|
+
console.log(`🧠 S007: Found ${semanticViolations.length} semantic violations in ${filePath}`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
} catch (error) {
|
|
68
|
+
console.error(`❌ S007: Semantic analysis failed for ${filePath}:`, error.message);
|
|
69
|
+
|
|
70
|
+
// Fallback to regex analysis if semantic fails
|
|
71
|
+
if (options.fallbackToRegex !== false) {
|
|
72
|
+
await this.fallbackToRegexAnalysis(filePath, options);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Fallback to regex analysis if semantic analysis fails
|
|
79
|
+
*/
|
|
80
|
+
async fallbackToRegexAnalysis(filePath, options) {
|
|
81
|
+
try {
|
|
82
|
+
if (this.verbose) {
|
|
83
|
+
console.log(`⚠️ S007: Falling back to regex analysis for ${filePath}`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Use the existing regex analyzer as fallback
|
|
87
|
+
const RegexAnalyzer = require('./analyzer');
|
|
88
|
+
const regexAnalyzer = new RegexAnalyzer();
|
|
89
|
+
|
|
90
|
+
const regexViolations = await regexAnalyzer.analyze([filePath], 'typescript', options);
|
|
91
|
+
|
|
92
|
+
// Add regex violations with lower confidence
|
|
93
|
+
for (const violation of regexViolations) {
|
|
94
|
+
this.addViolation({
|
|
95
|
+
...violation,
|
|
96
|
+
analysisMethod: 'regex_fallback',
|
|
97
|
+
confidence: 0.7, // Lower confidence for fallback
|
|
98
|
+
source: 'regex_analyzer'
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (this.verbose && regexViolations.length > 0) {
|
|
103
|
+
console.log(`🔧 S007: Found ${regexViolations.length} regex violations (fallback) in ${filePath}`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
} catch (fallbackError) {
|
|
107
|
+
console.error(`❌ S007: Fallback analysis also failed for ${filePath}:`, fallbackError.message);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Get supported file types
|
|
113
|
+
*/
|
|
114
|
+
isValidFileType(filePath) {
|
|
115
|
+
const supportedExtensions = ['.ts', '.tsx', '.js', '.jsx'];
|
|
116
|
+
const path = require('path');
|
|
117
|
+
const ext = path.extname(filePath);
|
|
118
|
+
return supportedExtensions.includes(ext);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Enhanced violation adding with semantic context
|
|
123
|
+
*/
|
|
124
|
+
addViolation(violation) {
|
|
125
|
+
const enhancedViolation = {
|
|
126
|
+
...violation,
|
|
127
|
+
|
|
128
|
+
// Add semantic metadata
|
|
129
|
+
analysisEngine: 'semantic',
|
|
130
|
+
analysisMethod: violation.analysisMethod || 'semantic',
|
|
131
|
+
confidence: violation.confidence || 0.9,
|
|
132
|
+
timestamp: Date.now(),
|
|
133
|
+
|
|
134
|
+
// Ensure required fields
|
|
135
|
+
ruleId: this.ruleId,
|
|
136
|
+
category: this.config.category,
|
|
137
|
+
severity: violation.severity || this.config.severity,
|
|
138
|
+
|
|
139
|
+
// Add semantic-specific fields
|
|
140
|
+
semanticContext: violation.symbolContext || {},
|
|
141
|
+
crossFileReferences: violation.crossFileReferences || [],
|
|
142
|
+
dataFlowAnalysis: violation.dataFlowAnalysis || null,
|
|
143
|
+
|
|
144
|
+
// Enhanced suggestions for semantic violations
|
|
145
|
+
suggestion: this.enhanceSemanticSuggestion(violation),
|
|
146
|
+
|
|
147
|
+
// Code context
|
|
148
|
+
codeSnippet: violation.codeSnippet || null,
|
|
149
|
+
|
|
150
|
+
// Metadata
|
|
151
|
+
metadata: {
|
|
152
|
+
engineVersion: '3.0',
|
|
153
|
+
analysisType: 'semantic',
|
|
154
|
+
symbolTableUsed: true,
|
|
155
|
+
crossFileAnalysis: this.config.crossFileAnalysis,
|
|
156
|
+
...violation.metadata
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
super.addViolation(enhancedViolation);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Enhance suggestions with semantic context
|
|
165
|
+
*/
|
|
166
|
+
enhanceSemanticSuggestion(violation) {
|
|
167
|
+
const baseSuggestion = violation.suggestion || 'Ensure OTP security best practices';
|
|
168
|
+
|
|
169
|
+
// Add context-specific suggestions based on semantic analysis
|
|
170
|
+
const contextSuggestions = [];
|
|
171
|
+
|
|
172
|
+
if (violation.symbolContext) {
|
|
173
|
+
const context = violation.symbolContext;
|
|
174
|
+
|
|
175
|
+
if (context.operation) {
|
|
176
|
+
contextSuggestions.push(`Consider replacing '${context.operation}' with a secure alternative`);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (context.dataFlow && context.dataFlow.length > 1) {
|
|
180
|
+
contextSuggestions.push('Review the data flow path to identify where encryption should be applied');
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (context.crossFileReferences && context.crossFileReferences.length > 0) {
|
|
184
|
+
contextSuggestions.push('Ensure security measures are consistent across all files using this OTP symbol');
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Combine base suggestion with context-specific suggestions
|
|
189
|
+
if (contextSuggestions.length > 0) {
|
|
190
|
+
return `${baseSuggestion}. Additional recommendations: ${contextSuggestions.join('; ')}.`;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return baseSuggestion;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Generate analysis report with semantic insights
|
|
198
|
+
*/
|
|
199
|
+
generateReport() {
|
|
200
|
+
const baseReport = super.generateReport();
|
|
201
|
+
|
|
202
|
+
// Add semantic-specific statistics
|
|
203
|
+
const semanticStats = this.calculateSemanticStats();
|
|
204
|
+
|
|
205
|
+
return {
|
|
206
|
+
...baseReport,
|
|
207
|
+
semanticAnalysis: {
|
|
208
|
+
enabled: true,
|
|
209
|
+
symbolTableUsed: true,
|
|
210
|
+
crossFileAnalysisPerformed: this.config.crossFileAnalysis,
|
|
211
|
+
dataFlowAnalysisPerformed: true,
|
|
212
|
+
statistics: semanticStats
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Calculate semantic analysis statistics
|
|
219
|
+
*/
|
|
220
|
+
calculateSemanticStats() {
|
|
221
|
+
const violations = this.getViolations();
|
|
222
|
+
|
|
223
|
+
const stats = {
|
|
224
|
+
totalViolations: violations.length,
|
|
225
|
+
violationsByType: {},
|
|
226
|
+
violationsByContext: {},
|
|
227
|
+
averageConfidence: 0,
|
|
228
|
+
crossFileViolations: 0,
|
|
229
|
+
dataFlowViolations: 0
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
// Analyze violation types and contexts
|
|
233
|
+
for (const violation of violations) {
|
|
234
|
+
// Count by type
|
|
235
|
+
const type = violation.type || 'unknown';
|
|
236
|
+
stats.violationsByType[type] = (stats.violationsByType[type] || 0) + 1;
|
|
237
|
+
|
|
238
|
+
// Count by context
|
|
239
|
+
if (violation.symbolContext && violation.symbolContext.usageContext) {
|
|
240
|
+
const context = violation.symbolContext.usageContext;
|
|
241
|
+
stats.violationsByContext[context] = (stats.violationsByContext[context] || 0) + 1;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Count cross-file violations
|
|
245
|
+
if (violation.crossFileReferences && violation.crossFileReferences.length > 0) {
|
|
246
|
+
stats.crossFileViolations++;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Count data flow violations
|
|
250
|
+
if (violation.dataFlowAnalysis) {
|
|
251
|
+
stats.dataFlowViolations++;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Calculate average confidence
|
|
256
|
+
if (violations.length > 0) {
|
|
257
|
+
const totalConfidence = violations.reduce((sum, v) => sum + (v.confidence || 0.9), 0);
|
|
258
|
+
stats.averageConfidence = totalConfidence / violations.length;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return stats;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Cleanup semantic resources
|
|
266
|
+
*/
|
|
267
|
+
async cleanup() {
|
|
268
|
+
if (this.semanticAnalyzer && typeof this.semanticAnalyzer.cleanup === 'function') {
|
|
269
|
+
await this.semanticAnalyzer.cleanup();
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
await super.cleanup();
|
|
273
|
+
|
|
274
|
+
if (this.verbose) {
|
|
275
|
+
console.log(`🧠 S007SemanticWrapper cleanup completed`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
module.exports = S007SemanticWrapper;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# S009 - No Insecure Encryption Modes, Padding, or Cryptographic Algorithms
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
This rule detects the usage of insecure cryptographic algorithms, cipher modes, and padding schemes that are vulnerable to various attacks and should not be used in production code.
|
|
6
|
+
|
|
7
|
+
## Rule Details
|
|
8
|
+
|
|
9
|
+
**Rule ID**: S009
|
|
10
|
+
**Category**: Security
|
|
11
|
+
**Severity**: Error
|
|
12
|
+
**Engine**: Heuristic
|
|
13
|
+
**OWASP**: A02:2021 - Cryptographic Failures
|
|
14
|
+
**CWE**: CWE-327 - Use of a Broken or Risky Cryptographic Algorithm
|
|
15
|
+
|
|
16
|
+
## Detected Vulnerabilities
|
|
17
|
+
|
|
18
|
+
### Insecure Symmetric Encryption Algorithms
|
|
19
|
+
- **DES** (Data Encryption Standard) - 56-bit key, easily broken
|
|
20
|
+
- **3DES/TripleDES** - Deprecated, vulnerable to Sweet32 attack
|
|
21
|
+
- **RC2** - Weak key schedule, vulnerable to related-key attacks
|
|
22
|
+
- **RC4** - Stream cipher with biases, deprecated
|
|
23
|
+
- **Blowfish** - Small block size, vulnerable to birthday attacks
|
|
24
|
+
|
|
25
|
+
### Insecure Cipher Modes
|
|
26
|
+
- **ECB** (Electronic Codebook) - Reveals patterns in plaintext
|
|
27
|
+
- **No encryption mode specified** - May default to insecure modes
|
|
28
|
+
|
|
29
|
+
### Insecure Hash Algorithms
|
|
30
|
+
- **MD2, MD4, MD5** - Vulnerable to collision attacks
|
|
31
|
+
- **SHA1** - Deprecated, collision attacks demonstrated
|
|
32
|
+
- **RIPEMD-128/160** - Weaker alternatives to SHA family
|
|
33
|
+
|
|
34
|
+
### Insecure Padding Schemes
|
|
35
|
+
- **PKCS#1 v1.5** - Vulnerable to padding oracle attacks
|
|
36
|
+
- **No padding** - Can lead to information leakage
|
|
37
|
+
|
|
38
|
+
### Insecure Key Derivation Functions
|
|
39
|
+
- **PBKDF1** - Limited output length, weak
|
|
40
|
+
- **Simple hash-based KDFs** - Vulnerable to dictionary attacks
|
|
41
|
+
|
|
42
|
+
## Examples
|
|
43
|
+
|
|
44
|
+
### ❌ Violations
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// Node.js crypto module violations
|
|
48
|
+
const cipher = crypto.createCipher('des', key);
|
|
49
|
+
const hash = crypto.createHash('md5');
|
|
50
|
+
const decipher = crypto.createDecipher('rc4', key);
|
|
51
|
+
|
|
52
|
+
// CryptoJS violations
|
|
53
|
+
const encrypted = CryptoJS.DES.encrypt(data, key);
|
|
54
|
+
const hash = CryptoJS.MD5(data);
|
|
55
|
+
const encrypted = CryptoJS.mode.ECB;
|
|
56
|
+
|
|
57
|
+
// Java violations
|
|
58
|
+
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
|
|
59
|
+
MessageDigest md = MessageDigest.getInstance("MD5");
|
|
60
|
+
|
|
61
|
+
// .NET violations
|
|
62
|
+
var des = new DESCryptoServiceProvider();
|
|
63
|
+
var md5 = MD5.Create();
|
|
64
|
+
|
|
65
|
+
// Configuration violations
|
|
66
|
+
const config = {
|
|
67
|
+
algorithm: 'des',
|
|
68
|
+
hash: 'md5',
|
|
69
|
+
cipher: 'rc4'
|
|
70
|
+
};
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### ✅ Secure Alternatives
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
// Secure Node.js crypto usage
|
|
77
|
+
const cipher = crypto.createCipher('aes-256-gcm', key);
|
|
78
|
+
const hash = crypto.createHash('sha256');
|
|
79
|
+
const decipher = crypto.createDecipher('aes-256-cbc', key);
|
|
80
|
+
|
|
81
|
+
// Secure CryptoJS usage
|
|
82
|
+
const encrypted = CryptoJS.AES.encrypt(data, key);
|
|
83
|
+
const hash = CryptoJS.SHA256(data);
|
|
84
|
+
const encrypted = CryptoJS.mode.GCM;
|
|
85
|
+
|
|
86
|
+
// Secure Java usage
|
|
87
|
+
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
|
|
88
|
+
MessageDigest md = MessageDigest.getInstance("SHA-256");
|
|
89
|
+
|
|
90
|
+
// Secure .NET usage
|
|
91
|
+
var aes = new AesCryptoServiceProvider();
|
|
92
|
+
var sha256 = SHA256.Create();
|
|
93
|
+
|
|
94
|
+
// Secure configuration
|
|
95
|
+
const config = {
|
|
96
|
+
algorithm: 'aes-256-gcm',
|
|
97
|
+
hash: 'sha256',
|
|
98
|
+
cipher: 'aes-256-cbc'
|
|
99
|
+
};
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## Supported Languages
|
|
103
|
+
|
|
104
|
+
- **JavaScript/TypeScript** - Node.js crypto, CryptoJS
|
|
105
|
+
- **Java** - javax.crypto, java.security
|
|
106
|
+
- **C#/.NET** - System.Security.Cryptography
|
|
107
|
+
- **Python** - cryptography, hashlib
|
|
108
|
+
- **Go** - crypto packages
|
|
109
|
+
- **Configuration files** - JSON, YAML, XML
|
|
110
|
+
|
|
111
|
+
## Detection Patterns
|
|
112
|
+
|
|
113
|
+
The rule uses heuristic analysis to detect:
|
|
114
|
+
|
|
115
|
+
1. **Direct API calls** with insecure algorithms
|
|
116
|
+
2. **Configuration settings** specifying weak crypto
|
|
117
|
+
3. **String literals** containing algorithm names
|
|
118
|
+
4. **Variable assignments** with insecure values
|
|
119
|
+
5. **Method chaining** with crypto operations
|
|
120
|
+
|
|
121
|
+
## False Positive Prevention
|
|
122
|
+
|
|
123
|
+
The rule excludes:
|
|
124
|
+
|
|
125
|
+
- **Comments and documentation**
|
|
126
|
+
- **Import/export statements**
|
|
127
|
+
- **Test files and mock data**
|
|
128
|
+
- **Educational/example code**
|
|
129
|
+
- **Variable names** (not actual usage)
|
|
130
|
+
- **Safe algorithm mentions** in secure contexts
|
|
131
|
+
|
|
132
|
+
## Remediation
|
|
133
|
+
|
|
134
|
+
### For Symmetric Encryption
|
|
135
|
+
- Use **AES-256** with secure modes (GCM, CBC)
|
|
136
|
+
- Ensure proper **initialization vectors** (IVs)
|
|
137
|
+
- Use **authenticated encryption** when possible
|
|
138
|
+
|
|
139
|
+
### For Hashing
|
|
140
|
+
- Use **SHA-256** or stronger (SHA-384, SHA-512)
|
|
141
|
+
- For passwords, use **bcrypt**, **scrypt**, or **Argon2**
|
|
142
|
+
- Avoid hashing for integrity without HMAC
|
|
143
|
+
|
|
144
|
+
### For Asymmetric Encryption
|
|
145
|
+
- Use **RSA-2048** or stronger, or **ECC P-256+**
|
|
146
|
+
- Use **OAEP padding** for RSA encryption
|
|
147
|
+
- Use **PSS padding** for RSA signatures
|
|
148
|
+
|
|
149
|
+
### For Key Derivation
|
|
150
|
+
- Use **PBKDF2** with high iteration counts (100,000+)
|
|
151
|
+
- Consider **scrypt** or **Argon2** for better security
|
|
152
|
+
- Use proper **salt** values
|
|
153
|
+
|
|
154
|
+
## References
|
|
155
|
+
|
|
156
|
+
- [OWASP Cryptographic Storage Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html)
|
|
157
|
+
- [NIST Cryptographic Standards](https://csrc.nist.gov/projects/cryptographic-standards-and-guidelines)
|
|
158
|
+
- [RFC 8018 - PKCS #5: Password-Based Cryptography Specification](https://tools.ietf.org/html/rfc8018)
|