@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.
Files changed (69) hide show
  1. package/config/rules/enhanced-rules-registry.json +101 -17
  2. package/config/rules/rules-registry-generated.json +22 -22
  3. package/origin-rules/security-en.md +351 -338
  4. package/package.json +1 -1
  5. package/rules/common/C003_no_vague_abbreviations/analyzer.js +73 -21
  6. package/rules/common/C017_constructor_logic/symbol-based-analyzer.js +206 -2
  7. package/rules/common/C024_no_scatter_hardcoded_constants/symbol-based-analyzer.js +553 -58
  8. package/rules/common/C029_catch_block_logging/analyzer.js +47 -12
  9. package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +35 -15
  10. package/rules/common/C041_no_sensitive_hardcode/symbol-based-analyzer.js +9 -5
  11. package/rules/security/S003_open_redirect_protection/README.md +371 -0
  12. package/rules/security/S003_open_redirect_protection/analyzer.js +135 -0
  13. package/rules/security/S003_open_redirect_protection/config.json +58 -0
  14. package/rules/security/S003_open_redirect_protection/symbol-based-analyzer.js +884 -0
  15. package/rules/security/S004_sensitive_data_logging/analyzer.js +135 -0
  16. package/rules/security/S004_sensitive_data_logging/config.json +62 -0
  17. package/rules/security/S004_sensitive_data_logging/symbol-based-analyzer.js +592 -0
  18. package/rules/security/S005_no_origin_auth/analyzer.js +97 -148
  19. package/rules/security/S005_no_origin_auth/config.json +28 -67
  20. package/rules/security/S005_no_origin_auth/symbol-based-analyzer.js +708 -0
  21. package/rules/security/S006_no_plaintext_recovery_codes/symbol-based-analyzer.js +170 -31
  22. package/rules/security/S010_no_insecure_encryption/analyzer.js +8 -2
  23. package/rules/security/S012_hardcoded_secrets/analyzer.js +149 -0
  24. package/rules/security/S012_hardcoded_secrets/config.json +75 -0
  25. package/rules/security/S012_hardcoded_secrets/symbol-based-analyzer.js +1204 -0
  26. package/rules/security/S013_tls_enforcement/symbol-based-analyzer.js +87 -0
  27. package/rules/security/S017_use_parameterized_queries/analyzer.js +11 -78
  28. package/rules/security/S017_use_parameterized_queries/symbol-based-analyzer.js +1146 -1
  29. package/rules/security/S019_smtp_injection_protection/analyzer.js +120 -0
  30. package/rules/security/S019_smtp_injection_protection/config.json +35 -0
  31. package/rules/security/S019_smtp_injection_protection/symbol-based-analyzer.js +687 -0
  32. package/rules/security/S020_no_eval_dynamic_code/analyzer.js +55 -130
  33. package/rules/security/S020_no_eval_dynamic_code/symbol-based-analyzer.js +4 -19
  34. package/rules/security/S022_escape_output_context/README.md +254 -0
  35. package/rules/security/S022_escape_output_context/analyzer.js +510 -0
  36. package/rules/security/S022_escape_output_context/config.json +229 -0
  37. package/rules/security/S023_no_json_injection/analyzer.js +15 -0
  38. package/rules/security/S023_no_json_injection/ast-analyzer.js +18 -3
  39. package/rules/security/S023_no_json_injection/config.json +133 -0
  40. package/rules/security/S024_xpath_xxe_protection/regex-based-analyzer.js +41 -0
  41. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +67 -8
  42. package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +29 -6
  43. package/rules/security/S029_csrf_protection/config.json +127 -0
  44. package/rules/security/S030_directory_browsing_protection/regex-based-analyzer.js +160 -28
  45. package/rules/security/S030_directory_browsing_protection/symbol-based-analyzer.js +81 -19
  46. package/rules/security/S031_secure_session_cookies/analyzer.js +20 -2
  47. package/rules/security/S031_secure_session_cookies/regex-based-analyzer.js +100 -0
  48. package/rules/security/S031_secure_session_cookies/symbol-based-analyzer.js +8 -1
  49. package/rules/security/S032_httponly_session_cookies/analyzer.js +2 -2
  50. package/rules/security/S032_httponly_session_cookies/regex-based-analyzer.js +115 -0
  51. package/rules/security/S032_httponly_session_cookies/symbol-based-analyzer.js +39 -10
  52. package/rules/security/S036_lfi_rfi_protection/analyzer.js +224 -0
  53. package/rules/security/S036_lfi_rfi_protection/config.json +20 -0
  54. package/rules/security/S040_session_fixation_protection/analyzer.js +153 -0
  55. package/rules/security/S040_session_fixation_protection/config.json +20 -0
  56. package/rules/security/S042_require_re_authentication_for_long_lived/README.md +83 -0
  57. package/rules/security/S042_require_re_authentication_for_long_lived/analyzer.js +153 -0
  58. package/rules/security/S042_require_re_authentication_for_long_lived/config.json +41 -0
  59. package/rules/security/S042_require_re_authentication_for_long_lived/symbol-based-analyzer.js +1139 -0
  60. package/rules/security/S043_password_changes_invalidate_all_sessions/README.md +107 -0
  61. package/rules/security/S043_password_changes_invalidate_all_sessions/analyzer.js +153 -0
  62. package/rules/security/S043_password_changes_invalidate_all_sessions/config.json +41 -0
  63. package/rules/security/S043_password_changes_invalidate_all_sessions/symbol-based-analyzer.js +541 -0
  64. package/docs/COMMAND-EXAMPLES.md +0 -390
  65. package/docs/FILE_LIMITS_COMPLETION_REPORT.md +0 -151
  66. package/docs/FOLDER_STRUCTURE.md +0 -59
  67. package/docs/SIMPLIFIED_USAGE_GUIDE.md +0 -208
  68. package/rules/security/S017_use_parameterized_queries/regex-based-analyzer.js +0 -541
  69. package/rules/security/S020_no_eval_dynamic_code/regex-based-analyzer.js +0 -307
@@ -0,0 +1,135 @@
1
+ /**
2
+ * S004 - Sensitive Data Logging Protection
3
+ *
4
+ * Main analyzer using symbol-based analysis to detect logging of sensitive
5
+ * information without proper redaction.
6
+ *
7
+ * Based on:
8
+ * - OWASP A09:2021 - Security Logging and Monitoring Failures
9
+ * - CWE-532: Insertion of Sensitive Information into Log File
10
+ */
11
+
12
+ // Command: node cli.js --rule=S004 --input=examples/rule-test-fixtures/rules/S004_sensitive_data_logging --engine=heuristic
13
+
14
+ const S004SymbolBasedAnalyzer = require("./symbol-based-analyzer");
15
+
16
+ class S004Analyzer {
17
+ constructor(options = {}) {
18
+ this.ruleId = "S004";
19
+ this.semanticEngine = options.semanticEngine || null;
20
+ this.verbose = options.verbose || false;
21
+
22
+ try {
23
+ this.symbolAnalyzer = new S004SymbolBasedAnalyzer(this.semanticEngine);
24
+ } catch (e) {
25
+ console.warn(`⚠ [S004] Failed to create symbol analyzer: ${e.message}`);
26
+ }
27
+ }
28
+
29
+ async initialize(semanticEngine) {
30
+ this.semanticEngine = semanticEngine;
31
+ if (this.symbolAnalyzer && this.symbolAnalyzer.initialize) {
32
+ await this.symbolAnalyzer.initialize(semanticEngine);
33
+ }
34
+ }
35
+
36
+ analyzeSingle(filePath, options = {}) {
37
+ return this.analyze([filePath], "typescript", options);
38
+ }
39
+
40
+ async analyze(files, language, options = {}) {
41
+ const violations = [];
42
+ for (const filePath of files) {
43
+ try {
44
+ const vs = await this.analyzeFile(filePath, options);
45
+ violations.push(...vs);
46
+ } catch (e) {
47
+ console.warn(`⚠ [S004] Analysis error for ${filePath}: ${e.message}`);
48
+ }
49
+ }
50
+ return violations;
51
+ }
52
+
53
+ async analyzeFile(filePath, options = {}) {
54
+ const violationMap = new Map();
55
+
56
+ if (!this.symbolAnalyzer) {
57
+ return [];
58
+ }
59
+
60
+ // Skip test files, build directories, and node_modules
61
+ if (this.shouldSkipFile(filePath)) {
62
+ return [];
63
+ }
64
+
65
+ try {
66
+ let sourceFile = null;
67
+ if (this.semanticEngine?.project) {
68
+ sourceFile = this.semanticEngine.project.getSourceFile(filePath);
69
+ }
70
+
71
+ if (!sourceFile) {
72
+ // Create temporary ts-morph source file
73
+ const fs = require("fs");
74
+ const path = require("path");
75
+ const { Project } = require("ts-morph");
76
+ if (!fs.existsSync(filePath)) {
77
+ throw new Error(`File not found: ${filePath}`);
78
+ }
79
+ const content = fs.readFileSync(filePath, "utf8");
80
+ const tmp = new Project({
81
+ useInMemoryFileSystem: true,
82
+ compilerOptions: { allowJs: true },
83
+ });
84
+ sourceFile = tmp.createSourceFile(path.basename(filePath), content);
85
+ }
86
+
87
+ if (sourceFile) {
88
+ const symbolViolations = await this.symbolAnalyzer.analyze(
89
+ sourceFile,
90
+ filePath
91
+ );
92
+ symbolViolations.forEach((v) => {
93
+ const key = `${v.line}:${v.column}:${v.message}`;
94
+ if (!violationMap.has(key)) violationMap.set(key, v);
95
+ });
96
+ }
97
+ } catch (e) {
98
+ console.warn(`⚠ [S004] Symbol analysis failed: ${e.message}`);
99
+ }
100
+
101
+ return Array.from(violationMap.values()).map((v) => ({
102
+ ...v,
103
+ filePath,
104
+ file: filePath,
105
+ }));
106
+ }
107
+
108
+ shouldSkipFile(filePath) {
109
+ const skipPatterns = [
110
+ "test/",
111
+ "tests/",
112
+ "__tests__/",
113
+ ".test.",
114
+ ".spec.",
115
+ "node_modules/",
116
+ "build/",
117
+ "dist/",
118
+ ".next/",
119
+ "coverage/",
120
+ "vendor/",
121
+ "mocks/",
122
+ ".mock.",
123
+ ];
124
+
125
+ return skipPatterns.some((pattern) => filePath.includes(pattern));
126
+ }
127
+
128
+ cleanup() {
129
+ if (this.symbolAnalyzer?.cleanup) {
130
+ this.symbolAnalyzer.cleanup();
131
+ }
132
+ }
133
+ }
134
+
135
+ module.exports = S004Analyzer;
@@ -0,0 +1,62 @@
1
+ {
2
+ "ruleId": "S004",
3
+ "name": "Sensitive Data Logging Protection",
4
+ "description": "Prevent logging of sensitive information like passwords, tokens, and payment data without proper redaction",
5
+ "category": "security",
6
+ "severity": "warning",
7
+ "languages": ["All languages"],
8
+ "tags": [
9
+ "security",
10
+ "owasp",
11
+ "logging",
12
+ "sensitive-data",
13
+ "pii",
14
+ "credentials",
15
+ "data-exposure"
16
+ ],
17
+ "enabled": true,
18
+ "fixable": false,
19
+ "engine": "heuristic",
20
+ "metadata": {
21
+ "owaspCategory": "A09:2021 - Security Logging and Monitoring Failures",
22
+ "cweId": "CWE-532",
23
+ "description": "Logging sensitive information without proper redaction can lead to data exposure through log files, monitoring systems, or centralized logging platforms. Logs may be shared with third parties, stored insecurely, or accessed by unauthorized personnel.",
24
+ "impact": "Medium - Data exposure, credential theft, compliance violations (GDPR, PCI-DSS)",
25
+ "likelihood": "High",
26
+ "remediation": "Mask or redact sensitive fields before logging. Use selective field logging (omit/pick) or implement log sanitization filters."
27
+ },
28
+ "patterns": {
29
+ "vulnerable": [
30
+ "console.log(password) without masking",
31
+ "logger.info(req.body) with sensitive fields",
32
+ "console.log(access_token) without redaction",
33
+ "logger.error(creditCard) unmasked",
34
+ "console.log(`Token: ${token}`) without masking",
35
+ "logger.info(req.headers) with Authorization header"
36
+ ],
37
+ "secure": [
38
+ "Use masking: console.log(password.replace(/./g, '*'))",
39
+ "Selective logging: logger.info(omit(req.body, ['password', 'token']))",
40
+ "Hash sensitive data: console.log({ tokenHash: hash(token) })",
41
+ "Partial redaction: logger.info({ card: card.substr(0, 4) + '****' })",
42
+ "Configure logger to filter sensitive fields automatically",
43
+ "Use structured logging with field-level redaction"
44
+ ]
45
+ },
46
+ "examples": {
47
+ "violations": [
48
+ "console.log('User password:', user.password);",
49
+ "logger.info('Request data:', req.body);",
50
+ "console.log(`Access token: ${accessToken}`);",
51
+ "logger.error('Auth failed:', { credentials: creds });",
52
+ "console.log(req.headers);"
53
+ ],
54
+ "fixes": [
55
+ "console.log('User login:', { username: user.username }); // Omit password",
56
+ "logger.info('Request data:', omit(req.body, ['password', 'secret']));",
57
+ "console.log(`Access token: ${accessToken.substr(0, 4)}****`);",
58
+ "logger.error('Auth failed:', { username: creds.username }); // Omit password",
59
+ "logger.info(omit(req.headers, ['authorization', 'cookie']));"
60
+ ]
61
+ }
62
+ }