@sun-asterisk/sunlint 1.3.26 → 1.3.28
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/config/rules/enhanced-rules-registry.json +101 -17
- package/config/rules/rules-registry-generated.json +22 -22
- package/origin-rules/security-en.md +351 -338
- package/package.json +1 -1
- package/rules/common/C003_no_vague_abbreviations/analyzer.js +73 -21
- package/rules/common/C017_constructor_logic/symbol-based-analyzer.js +206 -2
- package/rules/common/C024_no_scatter_hardcoded_constants/symbol-based-analyzer.js +553 -58
- package/rules/common/C029_catch_block_logging/analyzer.js +47 -12
- package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +35 -15
- package/rules/common/C041_no_sensitive_hardcode/symbol-based-analyzer.js +9 -5
- package/rules/security/S003_open_redirect_protection/README.md +371 -0
- package/rules/security/S003_open_redirect_protection/analyzer.js +135 -0
- package/rules/security/S003_open_redirect_protection/config.json +58 -0
- package/rules/security/S003_open_redirect_protection/symbol-based-analyzer.js +884 -0
- package/rules/security/S004_sensitive_data_logging/analyzer.js +135 -0
- package/rules/security/S004_sensitive_data_logging/config.json +62 -0
- package/rules/security/S004_sensitive_data_logging/symbol-based-analyzer.js +592 -0
- package/rules/security/S005_no_origin_auth/analyzer.js +97 -148
- package/rules/security/S005_no_origin_auth/config.json +28 -67
- package/rules/security/S005_no_origin_auth/symbol-based-analyzer.js +708 -0
- package/rules/security/S006_no_plaintext_recovery_codes/symbol-based-analyzer.js +170 -31
- package/rules/security/S010_no_insecure_encryption/analyzer.js +8 -2
- package/rules/security/S012_hardcoded_secrets/analyzer.js +149 -0
- package/rules/security/S012_hardcoded_secrets/config.json +75 -0
- package/rules/security/S012_hardcoded_secrets/symbol-based-analyzer.js +1204 -0
- package/rules/security/S013_tls_enforcement/symbol-based-analyzer.js +87 -0
- package/rules/security/S017_use_parameterized_queries/analyzer.js +11 -78
- package/rules/security/S017_use_parameterized_queries/symbol-based-analyzer.js +1146 -1
- package/rules/security/S019_smtp_injection_protection/analyzer.js +120 -0
- package/rules/security/S019_smtp_injection_protection/config.json +35 -0
- package/rules/security/S019_smtp_injection_protection/symbol-based-analyzer.js +687 -0
- package/rules/security/S020_no_eval_dynamic_code/analyzer.js +55 -130
- package/rules/security/S020_no_eval_dynamic_code/symbol-based-analyzer.js +4 -19
- package/rules/security/S022_escape_output_context/README.md +254 -0
- package/rules/security/S022_escape_output_context/analyzer.js +510 -0
- package/rules/security/S022_escape_output_context/config.json +229 -0
- package/rules/security/S023_no_json_injection/analyzer.js +15 -0
- package/rules/security/S023_no_json_injection/ast-analyzer.js +18 -3
- package/rules/security/S023_no_json_injection/config.json +133 -0
- package/rules/security/S024_xpath_xxe_protection/regex-based-analyzer.js +41 -0
- package/rules/security/S027_no_hardcoded_secrets/analyzer.js +67 -8
- package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +29 -6
- package/rules/security/S029_csrf_protection/config.json +127 -0
- package/rules/security/S030_directory_browsing_protection/regex-based-analyzer.js +160 -28
- package/rules/security/S030_directory_browsing_protection/symbol-based-analyzer.js +81 -19
- package/rules/security/S031_secure_session_cookies/analyzer.js +20 -2
- package/rules/security/S031_secure_session_cookies/regex-based-analyzer.js +100 -0
- package/rules/security/S031_secure_session_cookies/symbol-based-analyzer.js +8 -1
- package/rules/security/S032_httponly_session_cookies/analyzer.js +2 -2
- package/rules/security/S032_httponly_session_cookies/regex-based-analyzer.js +115 -0
- package/rules/security/S032_httponly_session_cookies/symbol-based-analyzer.js +39 -10
- package/rules/security/S036_lfi_rfi_protection/analyzer.js +224 -0
- package/rules/security/S036_lfi_rfi_protection/config.json +20 -0
- package/rules/security/S040_session_fixation_protection/analyzer.js +153 -0
- package/rules/security/S040_session_fixation_protection/config.json +20 -0
- package/rules/security/S042_require_re_authentication_for_long_lived/README.md +83 -0
- package/rules/security/S042_require_re_authentication_for_long_lived/analyzer.js +153 -0
- package/rules/security/S042_require_re_authentication_for_long_lived/config.json +41 -0
- package/rules/security/S042_require_re_authentication_for_long_lived/symbol-based-analyzer.js +1139 -0
- package/rules/security/S043_password_changes_invalidate_all_sessions/README.md +107 -0
- package/rules/security/S043_password_changes_invalidate_all_sessions/analyzer.js +153 -0
- package/rules/security/S043_password_changes_invalidate_all_sessions/config.json +41 -0
- package/rules/security/S043_password_changes_invalidate_all_sessions/symbol-based-analyzer.js +541 -0
- package/docs/COMMAND-EXAMPLES.md +0 -390
- package/docs/FILE_LIMITS_COMPLETION_REPORT.md +0 -151
- package/docs/FOLDER_STRUCTURE.md +0 -59
- package/docs/SIMPLIFIED_USAGE_GUIDE.md +0 -208
- package/rules/security/S017_use_parameterized_queries/regex-based-analyzer.js +0 -541
- package/rules/security/S020_no_eval_dynamic_code/regex-based-analyzer.js +0 -307
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rule S019: SMTP Injection Protection - Analyzer Wrapper
|
|
3
|
+
*
|
|
4
|
+
* This analyzer wraps the symbol-based analyzer to provide a consistent
|
|
5
|
+
* interface for the SunLint engine.
|
|
6
|
+
*/
|
|
7
|
+
// Command: node cli.js --rule=S019 --input=examples/rule-test-fixtures/rules/S019_smtp_injection_protection --engine=heuristic
|
|
8
|
+
|
|
9
|
+
const fs = require("fs");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const { Project } = require("ts-morph");
|
|
12
|
+
const S019SymbolBasedAnalyzer = require("./symbol-based-analyzer");
|
|
13
|
+
|
|
14
|
+
class S019Analyzer {
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.ruleId = "S019";
|
|
17
|
+
this.semanticEngine = options.semanticEngine || null;
|
|
18
|
+
this.symbolAnalyzer = new S019SymbolBasedAnalyzer(this.semanticEngine);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Analyze multiple files
|
|
23
|
+
*/
|
|
24
|
+
async analyze(files, language, options = {}) {
|
|
25
|
+
const violations = [];
|
|
26
|
+
|
|
27
|
+
for (const filePath of files) {
|
|
28
|
+
try {
|
|
29
|
+
const fileViolations = await this.analyzeFile(filePath, options);
|
|
30
|
+
violations.push(...fileViolations);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error(
|
|
33
|
+
`[S019] Error analyzing file ${filePath}:`,
|
|
34
|
+
error.message
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return violations;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Analyze a single file
|
|
44
|
+
*/
|
|
45
|
+
async analyzeFile(filePath, options = {}) {
|
|
46
|
+
// Skip files that shouldn't be analyzed
|
|
47
|
+
if (this.shouldSkipFile(filePath)) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// Check if file exists
|
|
53
|
+
if (!fs.existsSync(filePath)) {
|
|
54
|
+
return [];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
58
|
+
|
|
59
|
+
// Try to get source file from semantic engine
|
|
60
|
+
let sourceFile = this.semanticEngine?.project?.getSourceFile(filePath);
|
|
61
|
+
|
|
62
|
+
// If not available, create a temporary ts-morph source file
|
|
63
|
+
if (!sourceFile) {
|
|
64
|
+
const tempProject = new Project({
|
|
65
|
+
useInMemoryFileSystem: true,
|
|
66
|
+
compilerOptions: {
|
|
67
|
+
allowJs: true,
|
|
68
|
+
noLib: true,
|
|
69
|
+
target: 99, // ESNext
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
sourceFile = tempProject.createSourceFile(
|
|
74
|
+
path.basename(filePath),
|
|
75
|
+
content
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Run the symbol-based analyzer
|
|
80
|
+
const symbolViolations = await this.symbolAnalyzer.analyze(
|
|
81
|
+
sourceFile,
|
|
82
|
+
filePath
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Format violations to include file path
|
|
86
|
+
return symbolViolations.map((violation) => ({
|
|
87
|
+
...violation,
|
|
88
|
+
filePath: filePath,
|
|
89
|
+
file: filePath,
|
|
90
|
+
}));
|
|
91
|
+
} catch (error) {
|
|
92
|
+
console.error(`[S019] Error processing ${filePath}:`, error.message);
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Check if file should be skipped
|
|
99
|
+
*/
|
|
100
|
+
shouldSkipFile(filePath) {
|
|
101
|
+
const skipPatterns = [
|
|
102
|
+
"node_modules/",
|
|
103
|
+
"dist/",
|
|
104
|
+
"build/",
|
|
105
|
+
".next/",
|
|
106
|
+
"coverage/",
|
|
107
|
+
"__tests__/",
|
|
108
|
+
"test/",
|
|
109
|
+
"tests/",
|
|
110
|
+
".test.",
|
|
111
|
+
".spec.",
|
|
112
|
+
".min.js",
|
|
113
|
+
".bundle.js",
|
|
114
|
+
];
|
|
115
|
+
|
|
116
|
+
return skipPatterns.some((pattern) => filePath.includes(pattern));
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
module.exports = S019Analyzer;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"ruleId": "S019",
|
|
3
|
+
"name": "SMTP Injection Protection",
|
|
4
|
+
"description": "Detects potential SMTP/IMAP injection vulnerabilities by identifying unsanitized user input in email fields and direct SMTP protocol manipulation",
|
|
5
|
+
"category": "security",
|
|
6
|
+
"severity": "error",
|
|
7
|
+
"languages": ["typescript", "javascript"],
|
|
8
|
+
"tags": ["security", "owasp", "injection", "smtp", "email", "crlf"],
|
|
9
|
+
"enabled": true,
|
|
10
|
+
"fixable": false,
|
|
11
|
+
"engine": "heuristic",
|
|
12
|
+
"metadata": {
|
|
13
|
+
"owaspCategory": "A03:2021 - Injection",
|
|
14
|
+
"cweId": "CWE-93, CWE-144",
|
|
15
|
+
"impact": "High - Email spoofing, unauthorized email sending, header injection, spam",
|
|
16
|
+
"remediation": "Remove CRLF characters (\\r\\n) from user input before using in email fields. Use secure email service APIs (SendGrid, AWS SES, Mailgun) instead of direct SMTP manipulation. Validate email addresses with proper regex patterns.",
|
|
17
|
+
"references": [
|
|
18
|
+
"https://owasp.org/www-community/attacks/SMTP_Injection",
|
|
19
|
+
"https://cwe.mitre.org/data/definitions/93.html",
|
|
20
|
+
"https://cwe.mitre.org/data/definitions/144.html"
|
|
21
|
+
],
|
|
22
|
+
"examples": {
|
|
23
|
+
"vulnerable": [
|
|
24
|
+
"sendMail({ to: req.body.email, subject: req.body.subject })",
|
|
25
|
+
"message.setSubject(userInput)",
|
|
26
|
+
"const headers = 'To: ' + req.query.recipient"
|
|
27
|
+
],
|
|
28
|
+
"safe": [
|
|
29
|
+
"sendMail({ to: sanitize(req.body.email), subject: escape(req.body.subject) })",
|
|
30
|
+
"const cleanEmail = email.replace(/[\\r\\n]/g, '')",
|
|
31
|
+
"if (/^[a-zA-Z0-9@._-]+$/.test(email)) { sendMail({ to: email }) }"
|
|
32
|
+
]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|