@sun-asterisk/sunlint 1.3.1 → 1.3.3
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 +85 -0
- package/CONTRIBUTING.md +210 -1691
- package/README.md +5 -3
- package/config/rule-analysis-strategies.js +17 -1
- package/config/rules/enhanced-rules-registry.json +506 -1161
- package/config/rules/rules-registry-generated.json +1 -1
- package/core/analysis-orchestrator.js +167 -42
- package/core/auto-performance-manager.js +243 -0
- package/core/cli-action-handler.js +9 -1
- package/core/cli-program.js +19 -5
- package/core/constants/defaults.js +56 -0
- package/core/enhanced-rules-registry.js +2 -1
- package/core/performance-optimizer.js +271 -0
- package/core/semantic-engine.js +15 -3
- package/core/semantic-rule-base.js +4 -2
- package/docs/FILE_LIMITS_COMPLETION_REPORT.md +151 -0
- package/docs/FILE_LIMITS_EXPLANATION.md +190 -0
- package/docs/PERFORMANCE.md +311 -0
- package/docs/PERFORMANCE_MIGRATION_GUIDE.md +368 -0
- package/docs/PERFORMANCE_OPTIMIZATION_PLAN.md +255 -0
- package/docs/QUICK_FILE_LIMITS.md +64 -0
- package/docs/SIMPLIFIED_USAGE_GUIDE.md +208 -0
- package/engines/heuristic-engine.js +247 -9
- 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 +11 -7
- package/package.json +2 -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/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/C035_error_logging_context/analyzer.js +3 -1
- package/rules/common/C048_no_bypass_architectural_layers/analyzer.js +180 -0
- package/rules/common/C048_no_bypass_architectural_layers/config.json +50 -0
- package/rules/common/C048_no_bypass_architectural_layers/symbol-based-analyzer.js +235 -0
- package/rules/common/C052_parsing_or_data_transformation/analyzer.js +180 -0
- package/rules/common/C052_parsing_or_data_transformation/config.json +50 -0
- package/rules/common/C052_parsing_or_data_transformation/symbol-based-analyzer.js +132 -0
- package/rules/index.js +7 -1
- 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/S017_use_parameterized_queries/README.md +128 -0
- package/rules/security/S017_use_parameterized_queries/analyzer.js +286 -0
- package/rules/security/S017_use_parameterized_queries/config.json +109 -0
- package/rules/security/S017_use_parameterized_queries/regex-based-analyzer.js +541 -0
- package/rules/security/S017_use_parameterized_queries/symbol-based-analyzer.js +777 -0
- package/rules/security/S031_secure_session_cookies/README.md +127 -0
- package/rules/security/S031_secure_session_cookies/analyzer.js +245 -0
- package/rules/security/S031_secure_session_cookies/config.json +86 -0
- package/rules/security/S031_secure_session_cookies/regex-based-analyzer.js +196 -0
- package/rules/security/S031_secure_session_cookies/symbol-based-analyzer.js +1084 -0
- package/rules/security/S032_httponly_session_cookies/FRAMEWORK_SUPPORT.md +209 -0
- package/rules/security/S032_httponly_session_cookies/README.md +184 -0
- package/rules/security/S032_httponly_session_cookies/analyzer.js +282 -0
- package/rules/security/S032_httponly_session_cookies/config.json +96 -0
- package/rules/security/S032_httponly_session_cookies/regex-based-analyzer.js +715 -0
- package/rules/security/S032_httponly_session_cookies/symbol-based-analyzer.js +1348 -0
- package/rules/security/S033_samesite_session_cookies/README.md +227 -0
- package/rules/security/S033_samesite_session_cookies/analyzer.js +242 -0
- package/rules/security/S033_samesite_session_cookies/config.json +87 -0
- package/rules/security/S033_samesite_session_cookies/regex-based-analyzer.js +703 -0
- package/rules/security/S033_samesite_session_cookies/symbol-based-analyzer.js +732 -0
- package/rules/security/S034_host_prefix_session_cookies/README.md +204 -0
- package/rules/security/S034_host_prefix_session_cookies/analyzer.js +290 -0
- package/rules/security/S034_host_prefix_session_cookies/config.json +62 -0
- package/rules/security/S034_host_prefix_session_cookies/regex-based-analyzer.js +478 -0
- package/rules/security/S034_host_prefix_session_cookies/symbol-based-analyzer.js +277 -0
- package/rules/security/S035_path_session_cookies/README.md +257 -0
- package/rules/security/S035_path_session_cookies/analyzer.js +316 -0
- package/rules/security/S035_path_session_cookies/config.json +99 -0
- package/rules/security/S035_path_session_cookies/regex-based-analyzer.js +724 -0
- package/rules/security/S035_path_session_cookies/symbol-based-analyzer.js +373 -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/batch-processing-demo.js +334 -0
- package/scripts/consolidate-config.js +116 -0
- package/scripts/performance-test.js +541 -0
- package/scripts/quick-performance-test.js +108 -0
- package/config/rules/S027-categories.json +0 -122
- package/config/rules/rules-registry.json +0 -777
- package/rules/common/C006_function_naming/smart-analyzer.js +0 -503
|
@@ -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)
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Heuristic analyzer for S009 - No Insecure Encryption Modes, Padding, or Cryptographic Algorithms
|
|
3
|
+
* Purpose: Detect usage of insecure encryption algorithms, modes, and padding schemes
|
|
4
|
+
* Based on OWASP A02:2021 - Cryptographic Failures
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
class S009Analyzer {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.ruleId = 'S009';
|
|
10
|
+
this.ruleName = 'No Insecure Encryption Modes, Padding, or Cryptographic Algorithms';
|
|
11
|
+
this.description = 'Do not use insecure encryption modes, padding, or cryptographic algorithms';
|
|
12
|
+
|
|
13
|
+
// Insecure symmetric encryption algorithms
|
|
14
|
+
this.insecureSymmetricAlgorithms = [
|
|
15
|
+
'des', 'des-cbc', 'des-ecb', 'des-cfb', 'des-ofb',
|
|
16
|
+
'3des', 'des-ede', 'des-ede-cbc', 'des-ede-cfb', 'des-ede-ofb',
|
|
17
|
+
'des-ede3', 'des-ede3-cbc', 'des-ede3-cfb', 'des-ede3-ofb',
|
|
18
|
+
'rc2', 'rc2-cbc', 'rc2-ecb', 'rc2-cfb', 'rc2-ofb',
|
|
19
|
+
'rc4', 'rc4-40', 'rc4-hmac-md5',
|
|
20
|
+
'blowfish', 'bf', 'bf-cbc', 'bf-ecb', 'bf-cfb', 'bf-ofb'
|
|
21
|
+
];
|
|
22
|
+
|
|
23
|
+
// Insecure block cipher modes
|
|
24
|
+
this.insecureModes = [
|
|
25
|
+
'ecb', 'electronic-codebook'
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
// Insecure padding schemes
|
|
29
|
+
this.insecurePadding = [
|
|
30
|
+
'pkcs1', 'pkcs1_5', 'pkcs1-padding', 'rsa_pkcs1_padding',
|
|
31
|
+
'no-padding', 'nopadding'
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
// Insecure hash algorithms
|
|
35
|
+
this.insecureHashAlgorithms = [
|
|
36
|
+
'md2', 'md4', 'md5',
|
|
37
|
+
'sha', 'sha1', 'sha-1',
|
|
38
|
+
'ripemd', 'ripemd128', 'ripemd160'
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
// Insecure key derivation functions
|
|
42
|
+
this.insecureKDFs = [
|
|
43
|
+
'pbkdf1', 'simple-hash', 'plain-hash'
|
|
44
|
+
];
|
|
45
|
+
|
|
46
|
+
// Common crypto libraries and their patterns
|
|
47
|
+
this.cryptoPatterns = [
|
|
48
|
+
// Node.js crypto module
|
|
49
|
+
/crypto\.createCipher\(['"`]([^'"`]+)['"`]/i,
|
|
50
|
+
/crypto\.createDecipher\(['"`]([^'"`]+)['"`]/i,
|
|
51
|
+
/crypto\.createHash\(['"`]([^'"`]+)['"`]/i,
|
|
52
|
+
/crypto\.createHmac\(['"`]([^'"`]+)['"`]/i,
|
|
53
|
+
/crypto\.pbkdf2\(['"`]([^'"`]+)['"`]/i,
|
|
54
|
+
|
|
55
|
+
// CryptoJS patterns
|
|
56
|
+
/CryptoJS\.DES\./i,
|
|
57
|
+
/CryptoJS\.TripleDES\./i,
|
|
58
|
+
/CryptoJS\.RC4\./i,
|
|
59
|
+
/CryptoJS\.MD5\(/i,
|
|
60
|
+
/CryptoJS\.SHA1\(/i,
|
|
61
|
+
/CryptoJS\.mode\.ECB/i,
|
|
62
|
+
|
|
63
|
+
// Java crypto patterns
|
|
64
|
+
/Cipher\.getInstance\(['"`]([^'"`]+)['"`]/i,
|
|
65
|
+
/MessageDigest\.getInstance\(['"`]([^'"`]+)['"`]/i,
|
|
66
|
+
/Mac\.getInstance\(['"`]([^'"`]+)['"`]/i,
|
|
67
|
+
/KeyGenerator\.getInstance\(['"`]([^'"`]+)['"`]/i,
|
|
68
|
+
|
|
69
|
+
// .NET crypto patterns
|
|
70
|
+
/new\s+(DES|TripleDES|RC2|MD5|SHA1)CryptoServiceProvider/i,
|
|
71
|
+
/\.Create\(['"`](DES|TripleDES|RC2|MD5|SHA1)['"`]\)/i,
|
|
72
|
+
|
|
73
|
+
// OpenSSL command patterns
|
|
74
|
+
/-des\b|-des3\b|-rc4\b|-md5\b|-sha1\b/i,
|
|
75
|
+
|
|
76
|
+
// Generic algorithm references
|
|
77
|
+
/'(des|3des|rc4|md5|sha1|ecb)'/i,
|
|
78
|
+
/"(des|3des|rc4|md5|sha1|ecb)"/i,
|
|
79
|
+
/`(des|3des|rc4|md5|sha1|ecb)`/i,
|
|
80
|
+
|
|
81
|
+
// Configuration patterns
|
|
82
|
+
/algorithm\s*[:=]\s*['"`]([^'"`]+)['"`]/i,
|
|
83
|
+
/cipher\s*[:=]\s*['"`]([^'"`]+)['"`]/i,
|
|
84
|
+
/hash\s*[:=]\s*['"`]([^'"`]+)['"`]/i,
|
|
85
|
+
/encryption\s*[:=]\s*['"`]([^'"`]+)['"`]/i,
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
// Safe patterns to avoid false positives
|
|
89
|
+
this.safePatterns = [
|
|
90
|
+
// Comments and documentation
|
|
91
|
+
/\/\/|\/\*|\*\/|@param|@return|@example|@deprecated|TODO|FIXME/i,
|
|
92
|
+
|
|
93
|
+
// Import/export statements
|
|
94
|
+
/import|export|require|module\.exports/i,
|
|
95
|
+
|
|
96
|
+
// Type definitions
|
|
97
|
+
/interface|type|enum|class.*\{/i,
|
|
98
|
+
|
|
99
|
+
// Test files and mock data
|
|
100
|
+
/\.test\.|\.spec\.|mock|stub|fake|dummy/i,
|
|
101
|
+
|
|
102
|
+
// Safe modern algorithms mentioned in context
|
|
103
|
+
/aes|rsa-oaep|sha256|sha384|sha512|bcrypt|scrypt|argon2|pbkdf2/i,
|
|
104
|
+
|
|
105
|
+
// Configuration examples or documentation
|
|
106
|
+
/example|sample|demo|deprecated|legacy|old|insecure|weak|avoid|don't use|do not use/i,
|
|
107
|
+
|
|
108
|
+
// Variable names that might contain keywords but are safe
|
|
109
|
+
/const\s+\w*[Nn]ame|let\s+\w*[Nn]ame|var\s+\w*[Nn]ame/i,
|
|
110
|
+
|
|
111
|
+
// Safe usage in educational context
|
|
112
|
+
/educational|tutorial|learning|history|comparison/i,
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
// Context patterns that increase confidence of violations
|
|
116
|
+
this.violationContexts = [
|
|
117
|
+
// Direct algorithm usage
|
|
118
|
+
/encrypt|decrypt|cipher|hash|digest|sign|verify/i,
|
|
119
|
+
|
|
120
|
+
// Configuration settings
|
|
121
|
+
/config|setting|option|parameter/i,
|
|
122
|
+
|
|
123
|
+
// API calls
|
|
124
|
+
/\.create|\.get|\.set|\.use|\.apply/i,
|
|
125
|
+
|
|
126
|
+
// Assignment patterns
|
|
127
|
+
/=\s*['"`]|:\s*['"`]/,
|
|
128
|
+
|
|
129
|
+
// Function calls
|
|
130
|
+
/\([^)]*['"`][^'"`]*['"`][^)]*\)/,
|
|
131
|
+
];
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async analyze(files, language, options = {}) {
|
|
135
|
+
const violations = [];
|
|
136
|
+
|
|
137
|
+
for (const filePath of files) {
|
|
138
|
+
// Skip test files, build directories, and node_modules
|
|
139
|
+
if (this.shouldSkipFile(filePath)) {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
try {
|
|
144
|
+
const content = require('fs').readFileSync(filePath, 'utf8');
|
|
145
|
+
const fileViolations = this.analyzeFile(content, filePath, options);
|
|
146
|
+
violations.push(...fileViolations);
|
|
147
|
+
} catch (error) {
|
|
148
|
+
if (options.verbose) {
|
|
149
|
+
console.warn(`⚠️ Failed to analyze ${filePath}: ${error.message}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return violations;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
shouldSkipFile(filePath) {
|
|
158
|
+
const skipPatterns = [
|
|
159
|
+
'test/', 'tests/', '__tests__/', '.test.', '.spec.',
|
|
160
|
+
'node_modules/', 'build/', 'dist/', '.next/', 'coverage/',
|
|
161
|
+
'vendor/', 'mocks/', '.mock.', 'docs/', 'documentation/'
|
|
162
|
+
];
|
|
163
|
+
|
|
164
|
+
return skipPatterns.some(pattern => filePath.includes(pattern));
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
analyzeFile(content, filePath, options = {}) {
|
|
168
|
+
const violations = [];
|
|
169
|
+
const lines = content.split('\n');
|
|
170
|
+
|
|
171
|
+
lines.forEach((line, index) => {
|
|
172
|
+
const lineNumber = index + 1;
|
|
173
|
+
const trimmedLine = line.trim();
|
|
174
|
+
|
|
175
|
+
// Skip comments, imports, and empty lines
|
|
176
|
+
if (this.shouldSkipLine(trimmedLine)) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Check for insecure cryptographic usage
|
|
181
|
+
const violation = this.checkForInsecureCrypto(line, lineNumber, filePath);
|
|
182
|
+
if (violation) {
|
|
183
|
+
violations.push(violation);
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
return violations;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
shouldSkipLine(line) {
|
|
191
|
+
// Skip comments, imports, and other non-code lines
|
|
192
|
+
return (
|
|
193
|
+
line.length === 0 ||
|
|
194
|
+
line.startsWith('//') ||
|
|
195
|
+
line.startsWith('/*') ||
|
|
196
|
+
line.startsWith('*') ||
|
|
197
|
+
line.startsWith('import ') ||
|
|
198
|
+
line.startsWith('export ') ||
|
|
199
|
+
line.startsWith('require(') ||
|
|
200
|
+
line.includes('module.exports') ||
|
|
201
|
+
line.startsWith('#') // Python/shell comments
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
checkForInsecureCrypto(line, lineNumber, filePath) {
|
|
206
|
+
// First check if line contains safe patterns (early exit)
|
|
207
|
+
if (this.containsSafePattern(line)) {
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Check each crypto pattern
|
|
212
|
+
for (const pattern of this.cryptoPatterns) {
|
|
213
|
+
const match = pattern.exec(line);
|
|
214
|
+
if (match) {
|
|
215
|
+
const algorithm = match[1] ? match[1].toLowerCase() : '';
|
|
216
|
+
const fullMatch = match[0];
|
|
217
|
+
|
|
218
|
+
// Check if the algorithm is insecure
|
|
219
|
+
const insecureAlgorithm = this.identifyInsecureAlgorithm(algorithm, fullMatch);
|
|
220
|
+
if (insecureAlgorithm) {
|
|
221
|
+
// Additional context check to reduce false positives
|
|
222
|
+
if (this.hasViolationContext(line)) {
|
|
223
|
+
return {
|
|
224
|
+
ruleId: this.ruleId,
|
|
225
|
+
severity: 'error',
|
|
226
|
+
message: `Insecure cryptographic algorithm detected: ${insecureAlgorithm.algorithm}. ${insecureAlgorithm.reason}`,
|
|
227
|
+
line: lineNumber,
|
|
228
|
+
column: line.indexOf(fullMatch) + 1,
|
|
229
|
+
filePath: filePath,
|
|
230
|
+
type: insecureAlgorithm.type,
|
|
231
|
+
algorithm: insecureAlgorithm.algorithm,
|
|
232
|
+
details: insecureAlgorithm.recommendation
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return null;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
containsSafePattern(line) {
|
|
243
|
+
return this.safePatterns.some(pattern => pattern.test(line));
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
identifyInsecureAlgorithm(algorithm, fullMatch) {
|
|
247
|
+
const lowerAlgorithm = algorithm.toLowerCase();
|
|
248
|
+
const lowerFullMatch = fullMatch.toLowerCase();
|
|
249
|
+
|
|
250
|
+
// Check symmetric encryption algorithms
|
|
251
|
+
if (this.insecureSymmetricAlgorithms.some(alg =>
|
|
252
|
+
lowerAlgorithm.includes(alg) || lowerFullMatch.includes(alg))) {
|
|
253
|
+
const matchedAlg = this.insecureSymmetricAlgorithms.find(alg =>
|
|
254
|
+
lowerAlgorithm.includes(alg) || lowerFullMatch.includes(alg));
|
|
255
|
+
|
|
256
|
+
return {
|
|
257
|
+
algorithm: matchedAlg.toUpperCase(),
|
|
258
|
+
type: 'insecure_symmetric_encryption',
|
|
259
|
+
reason: 'This algorithm is cryptographically weak and vulnerable to attacks.',
|
|
260
|
+
recommendation: 'Use AES-256-GCM or ChaCha20-Poly1305 for symmetric encryption.'
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Check block cipher modes
|
|
265
|
+
if (this.insecureModes.some(mode =>
|
|
266
|
+
lowerAlgorithm.includes(mode) || lowerFullMatch.includes(mode))) {
|
|
267
|
+
return {
|
|
268
|
+
algorithm: 'ECB Mode',
|
|
269
|
+
type: 'insecure_cipher_mode',
|
|
270
|
+
reason: 'ECB mode reveals patterns in plaintext and is not semantically secure.',
|
|
271
|
+
recommendation: 'Use CBC, CTR, or GCM modes with proper initialization vectors.'
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// Check hash algorithms
|
|
276
|
+
if (this.insecureHashAlgorithms.some(hash =>
|
|
277
|
+
lowerAlgorithm.includes(hash) || lowerFullMatch.includes(hash))) {
|
|
278
|
+
const matchedHash = this.insecureHashAlgorithms.find(hash =>
|
|
279
|
+
lowerAlgorithm.includes(hash) || lowerFullMatch.includes(hash));
|
|
280
|
+
|
|
281
|
+
return {
|
|
282
|
+
algorithm: matchedHash.toUpperCase(),
|
|
283
|
+
type: 'insecure_hash_algorithm',
|
|
284
|
+
reason: 'This hash algorithm is vulnerable to collision attacks.',
|
|
285
|
+
recommendation: 'Use SHA-256, SHA-384, or SHA-512 for cryptographic hashing.'
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Check padding schemes
|
|
290
|
+
if (this.insecurePadding.some(padding =>
|
|
291
|
+
lowerAlgorithm.includes(padding) || lowerFullMatch.includes(padding))) {
|
|
292
|
+
return {
|
|
293
|
+
algorithm: 'PKCS#1 v1.5 Padding',
|
|
294
|
+
type: 'insecure_padding_scheme',
|
|
295
|
+
reason: 'PKCS#1 v1.5 padding is vulnerable to padding oracle attacks.',
|
|
296
|
+
recommendation: 'Use OAEP padding for RSA encryption.'
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Check key derivation functions
|
|
301
|
+
if (this.insecureKDFs.some(kdf =>
|
|
302
|
+
lowerAlgorithm.includes(kdf) || lowerFullMatch.includes(kdf))) {
|
|
303
|
+
return {
|
|
304
|
+
algorithm: 'PBKDF1',
|
|
305
|
+
type: 'insecure_key_derivation',
|
|
306
|
+
reason: 'This key derivation function is weak and vulnerable to attacks.',
|
|
307
|
+
recommendation: 'Use PBKDF2 with high iteration count, scrypt, or Argon2.'
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
hasViolationContext(line) {
|
|
315
|
+
return this.violationContexts.some(context => context.test(line));
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
module.exports = S009Analyzer;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ruleId": "S009",
|
|
3
|
+
"name": "No Insecure Encryption Modes, Padding, or Cryptographic Algorithms",
|
|
4
|
+
"description": "Do not use insecure encryption modes, padding, or cryptographic algorithms",
|
|
5
|
+
"category": "security",
|
|
6
|
+
"severity": "error",
|
|
7
|
+
"languages": ["All languages"],
|
|
8
|
+
"tags": ["security", "owasp", "cryptographic-failures", "encryption"],
|
|
9
|
+
"enabled": true,
|
|
10
|
+
"fixable": false,
|
|
11
|
+
"engine": "heuristic",
|
|
12
|
+
"metadata": {
|
|
13
|
+
"owaspCategory": "A02:2021 - Cryptographic Failures",
|
|
14
|
+
"cweId": "CWE-327",
|
|
15
|
+
"description": "Using insecure cryptographic algorithms, cipher modes, or padding schemes can lead to data exposure and compromise. Weak algorithms like DES, 3DES, RC4, MD5, and SHA1 are vulnerable to various attacks including collision attacks, brute force, and cryptanalysis.",
|
|
16
|
+
"impact": "High - Data exposure, integrity compromise, authentication bypass",
|
|
17
|
+
"likelihood": "Medium",
|
|
18
|
+
"remediation": "Use strong cryptographic algorithms (AES-256, RSA-2048+, SHA-256+), secure cipher modes (GCM, CBC with IV), and proper padding schemes (OAEP)"
|
|
19
|
+
},
|
|
20
|
+
"patterns": {
|
|
21
|
+
"vulnerable": [
|
|
22
|
+
"Using DES or 3DES for encryption",
|
|
23
|
+
"Using RC4 stream cipher",
|
|
24
|
+
"Using ECB cipher mode",
|
|
25
|
+
"Using MD5 or SHA1 for cryptographic purposes",
|
|
26
|
+
"Using PKCS#1 v1.5 padding for RSA",
|
|
27
|
+
"Using weak key derivation functions"
|
|
28
|
+
],
|
|
29
|
+
"secure": [
|
|
30
|
+
"Using AES-256-GCM for symmetric encryption",
|
|
31
|
+
"Using RSA with OAEP padding",
|
|
32
|
+
"Using SHA-256 or stronger hash algorithms",
|
|
33
|
+
"Using proper cipher modes with initialization vectors",
|
|
34
|
+
"Using PBKDF2, scrypt, or Argon2 for key derivation"
|
|
35
|
+
]
|
|
36
|
+
},
|
|
37
|
+
"examples": {
|
|
38
|
+
"violations": [
|
|
39
|
+
"crypto.createCipher('des', key);",
|
|
40
|
+
"crypto.createHash('md5');",
|
|
41
|
+
"Cipher.getInstance('DES/ECB/PKCS5Padding');",
|
|
42
|
+
"CryptoJS.DES.encrypt(data, key);",
|
|
43
|
+
"algorithm: 'rc4'",
|
|
44
|
+
"new DESCryptoServiceProvider();"
|
|
45
|
+
],
|
|
46
|
+
"fixes": [
|
|
47
|
+
"crypto.createCipher('aes-256-gcm', key);",
|
|
48
|
+
"crypto.createHash('sha256');",
|
|
49
|
+
"Cipher.getInstance('AES/GCM/NoPadding');",
|
|
50
|
+
"CryptoJS.AES.encrypt(data, key);",
|
|
51
|
+
"algorithm: 'aes-256-gcm'",
|
|
52
|
+
"new AesCryptoServiceProvider();"
|
|
53
|
+
]
|
|
54
|
+
}
|
|
55
|
+
}
|