@sun-asterisk/sunlint 1.3.26 → 1.3.27

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 (43) hide show
  1. package/config/rules/enhanced-rules-registry.json +99 -16
  2. package/package.json +1 -1
  3. package/rules/common/C029_catch_block_logging/analyzer.js +47 -12
  4. package/rules/common/C033_separate_service_repository/symbol-based-analyzer.js +35 -15
  5. package/rules/security/S003_open_redirect_protection/README.md +371 -0
  6. package/rules/security/S003_open_redirect_protection/analyzer.js +135 -0
  7. package/rules/security/S003_open_redirect_protection/config.json +58 -0
  8. package/rules/security/S003_open_redirect_protection/symbol-based-analyzer.js +884 -0
  9. package/rules/security/S004_sensitive_data_logging/analyzer.js +135 -0
  10. package/rules/security/S004_sensitive_data_logging/config.json +62 -0
  11. package/rules/security/S004_sensitive_data_logging/symbol-based-analyzer.js +592 -0
  12. package/rules/security/S012_hardcoded_secrets/analyzer.js +149 -0
  13. package/rules/security/S012_hardcoded_secrets/config.json +75 -0
  14. package/rules/security/S012_hardcoded_secrets/symbol-based-analyzer.js +1204 -0
  15. package/rules/security/S019_smtp_injection_protection/analyzer.js +120 -0
  16. package/rules/security/S019_smtp_injection_protection/config.json +35 -0
  17. package/rules/security/S019_smtp_injection_protection/symbol-based-analyzer.js +687 -0
  18. package/rules/security/S022_escape_output_context/README.md +254 -0
  19. package/rules/security/S022_escape_output_context/analyzer.js +510 -0
  20. package/rules/security/S022_escape_output_context/config.json +229 -0
  21. package/rules/security/S023_no_json_injection/analyzer.js +15 -0
  22. package/rules/security/S023_no_json_injection/ast-analyzer.js +18 -3
  23. package/rules/security/S023_no_json_injection/config.json +133 -0
  24. package/rules/security/S024_xpath_xxe_protection/regex-based-analyzer.js +41 -0
  25. package/rules/security/S027_no_hardcoded_secrets/analyzer.js +67 -8
  26. package/rules/security/S027_no_hardcoded_secrets/categorized-analyzer.js +29 -6
  27. package/rules/security/S029_csrf_protection/config.json +127 -0
  28. package/rules/security/S030_directory_browsing_protection/regex-based-analyzer.js +160 -28
  29. package/rules/security/S030_directory_browsing_protection/symbol-based-analyzer.js +81 -19
  30. package/rules/security/S031_secure_session_cookies/analyzer.js +20 -2
  31. package/rules/security/S031_secure_session_cookies/regex-based-analyzer.js +100 -0
  32. package/rules/security/S031_secure_session_cookies/symbol-based-analyzer.js +8 -1
  33. package/rules/security/S032_httponly_session_cookies/analyzer.js +2 -2
  34. package/rules/security/S032_httponly_session_cookies/regex-based-analyzer.js +115 -0
  35. package/rules/security/S032_httponly_session_cookies/symbol-based-analyzer.js +39 -10
  36. package/rules/security/S036_lfi_rfi_protection/analyzer.js +224 -0
  37. package/rules/security/S036_lfi_rfi_protection/config.json +20 -0
  38. package/rules/security/S040_session_fixation_protection/analyzer.js +153 -0
  39. package/rules/security/S040_session_fixation_protection/config.json +20 -0
  40. package/rules/security/S042_require_re_authentication_for_long_lived/README.md +83 -0
  41. package/rules/security/S042_require_re_authentication_for_long_lived/analyzer.js +153 -0
  42. package/rules/security/S042_require_re_authentication_for_long_lived/config.json +41 -0
  43. package/rules/security/S042_require_re_authentication_for_long_lived/symbol-based-analyzer.js +1139 -0
@@ -0,0 +1,254 @@
1
+ # S022 - Escape Data Properly Based on Output Context
2
+
3
+ ## Overview
4
+
5
+ **Rule ID:** S022
6
+ **Category:** Security
7
+ **Severity:** Error
8
+ **OWASP:** A03:2021 – Injection (XSS)
9
+ **CWE:** CWE-79 - Improper Neutralization of Input During Web Page Generation
10
+
11
+ ## Description
12
+
13
+ This rule ensures that all data output to different contexts (HTML, JavaScript, URL, CSS, attributes) is properly escaped or sanitized to prevent Cross-Site Scripting (XSS) attacks. Different output contexts require different escaping mechanisms.
14
+
15
+ XSS vulnerabilities occur when untrusted data is included in a web page without proper validation or escaping, allowing attackers to inject malicious scripts that execute in victims' browsers.
16
+
17
+ ## Why This Matters
18
+
19
+ ### Security Impact
20
+
21
+ - **Data Theft**: Attackers can steal sensitive information (cookies, session tokens, credentials)
22
+ - **Account Hijacking**: Session tokens can be stolen for account takeover
23
+ - **Malware Distribution**: Inject scripts that download malware
24
+ - **Defacement**: Modify page content to damage reputation
25
+ - **Phishing**: Redirect users to malicious sites
26
+
27
+ ### Context-Specific Escaping
28
+
29
+ Different contexts require different escaping methods:
30
+
31
+ 1. **HTML Context**: `<div>{data}</div>` → Escape `<`, `>`, `&`, `"`, `'`
32
+ 2. **JavaScript Context**: `<script>var x = '{data}'</script>` → JSON encoding
33
+ 3. **URL Context**: `<a href="{data}">` → URL encoding + validation
34
+ 4. **CSS Context**: `<style>{data}</style>` → CSS escaping
35
+ 5. **Attribute Context**: `<div title="{data}">` → Attribute escaping
36
+
37
+ ## What It Detects
38
+
39
+ ### 1. HTML Context Violations
40
+
41
+ ```javascript
42
+ // ❌ BAD: Unsafe innerHTML with user input
43
+ element.innerHTML = req.query.name;
44
+ element.outerHTML = userInput;
45
+ document.write(req.body.content);
46
+
47
+ // ❌ BAD: React dangerouslySetInnerHTML without sanitization
48
+ <div dangerouslySetInnerHTML={{__html: userInput}} />
49
+
50
+ // ❌ BAD: Vue v-html without sanitization
51
+ <div v-html="userInput"></div>
52
+
53
+ // ✅ GOOD: Use textContent for plain text
54
+ element.textContent = req.query.name;
55
+
56
+ // ✅ GOOD: Sanitize HTML with DOMPurify
57
+ element.innerHTML = DOMPurify.sanitize(userInput);
58
+
59
+ // ✅ GOOD: React with sanitization
60
+ <div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(userInput)}} />
61
+
62
+ // ✅ GOOD: Vue with v-text
63
+ <div v-text="userInput"></div>
64
+ ```
65
+
66
+ ### 2. JavaScript Context Violations
67
+
68
+ ```javascript
69
+ // ❌ BAD: eval with user input
70
+ eval(req.query.code);
71
+ new Function(userInput)();
72
+ setTimeout(req.body.script, 1000);
73
+
74
+ // ❌ BAD: Even dynamic eval is dangerous
75
+ const code = getCodeFromSomewhere();
76
+ eval(code);
77
+
78
+ // ✅ GOOD: Never use eval - use JSON.parse for data
79
+ const data = JSON.parse(jsonString);
80
+
81
+ // ✅ GOOD: Use safe alternatives
82
+ const func = functionMap[safeKey];
83
+ func();
84
+ ```
85
+
86
+ ### 3. URL Context Violations
87
+
88
+ ```javascript
89
+ // ❌ BAD: Unvalidated URL redirect (Open Redirect)
90
+ window.location = req.query.redirect;
91
+ location.href = userInput;
92
+ window.open(req.query.url);
93
+
94
+ // ✅ GOOD: Validate URLs against whitelist
95
+ const allowedHosts = ['example.com', 'trusted.com'];
96
+ const url = new URL(req.query.redirect);
97
+ if (allowedHosts.includes(url.hostname)) {
98
+ window.location = url.href;
99
+ }
100
+
101
+ // ✅ GOOD: Use relative URLs only
102
+ if (redirectUrl.startsWith('/')) {
103
+ window.location = redirectUrl;
104
+ }
105
+ ```
106
+
107
+ ### 4. Event Handler Violations
108
+
109
+ ```javascript
110
+ // ❌ BAD: Dynamic event handler with user input
111
+ element.setAttribute('onclick', userInput);
112
+ element.setAttribute('onerror', req.query.handler);
113
+
114
+ // ✅ GOOD: Use addEventListener
115
+ element.addEventListener('click', function() {
116
+ // Safe handler logic
117
+ });
118
+
119
+ // ✅ GOOD: Use data attributes
120
+ element.dataset.action = userInput;
121
+ ```
122
+
123
+ ## Framework-Specific Guidance
124
+
125
+ ### React
126
+
127
+ ```javascript
128
+ // ❌ Avoid dangerouslySetInnerHTML
129
+ <div dangerouslySetInnerHTML={{__html: userInput}} />
130
+
131
+ // ✅ Use children or textContent
132
+ <div>{userInput}</div>
133
+
134
+ // ✅ If HTML is needed, sanitize it
135
+ import DOMPurify from 'dompurify';
136
+ <div dangerouslySetInnerHTML={{__html: DOMPurify.sanitize(html)}} />
137
+ ```
138
+
139
+ ### Vue
140
+
141
+ ```javascript
142
+ // ❌ Avoid v-html with user input
143
+ <div v-html="userInput"></div>
144
+
145
+ // ✅ Use interpolation or v-text
146
+ <div>{{ userInput }}</div>
147
+ <div v-text="userInput"></div>
148
+
149
+ // ✅ If HTML is needed, sanitize it
150
+ <div v-html="$sanitize(html)"></div>
151
+ ```
152
+
153
+ ### Angular
154
+
155
+ ```javascript
156
+ // ❌ Avoid [innerHTML] with user input
157
+ <div [innerHTML]="userInput"></div>
158
+
159
+ // ✅ Use interpolation
160
+ <div>{{ userInput }}</div>
161
+
162
+ // ✅ Use DomSanitizer if HTML is needed
163
+ import { DomSanitizer } from '@angular/platform-browser';
164
+ this.safeHtml = this.sanitizer.sanitize(SecurityContext.HTML, html);
165
+ ```
166
+
167
+ ## Recommended Sanitization Libraries
168
+
169
+ 1. **DOMPurify** (Browser & Node.js)
170
+ ```javascript
171
+ import DOMPurify from 'dompurify';
172
+ const clean = DOMPurify.sanitize(dirty);
173
+ ```
174
+
175
+ 2. **xss** (Node.js)
176
+ ```javascript
177
+ const xss = require('xss');
178
+ const clean = xss(dirty);
179
+ ```
180
+
181
+ 3. **validator.js** (Node.js)
182
+ ```javascript
183
+ const validator = require('validator');
184
+ const escaped = validator.escape(input);
185
+ ```
186
+
187
+ ## Safe Alternatives
188
+
189
+ | Unsafe Method | Safe Alternative |
190
+ |--------------|------------------|
191
+ | `innerHTML` | `textContent` or `innerText` |
192
+ | `outerHTML` | `textContent` |
193
+ | `document.write()` | DOM manipulation methods |
194
+ | `eval()` | `JSON.parse()` |
195
+ | `setTimeout(string)` | `setTimeout(function)` |
196
+ | `dangerouslySetInnerHTML` | React children or DOMPurify |
197
+ | `v-html` | `v-text` or sanitization |
198
+
199
+ ## How to Fix
200
+
201
+ 1. **Identify the Context**: Determine where the data will be output (HTML, JS, URL, etc.)
202
+ 2. **Choose Appropriate Method**:
203
+ - HTML: Use `textContent` or sanitize with DOMPurify
204
+ - JavaScript: Avoid dynamic code execution
205
+ - URL: Validate and whitelist
206
+ 3. **Apply Escaping/Sanitization**: Use context-appropriate escaping
207
+ 4. **Test**: Verify XSS payloads don't execute
208
+
209
+ ## Testing
210
+
211
+ Create test files with common XSS payloads:
212
+
213
+ ```javascript
214
+ const testPayloads = [
215
+ '<script>alert("XSS")</script>',
216
+ '<img src=x onerror=alert("XSS")>',
217
+ 'javascript:alert("XSS")',
218
+ '<svg onload=alert("XSS")>',
219
+ '"><script>alert("XSS")</script>',
220
+ ];
221
+
222
+ // Test that these are properly escaped/sanitized
223
+ testPayloads.forEach(payload => {
224
+ const result = sanitize(payload);
225
+ assert(!result.includes('<script'));
226
+ });
227
+ ```
228
+
229
+ ## References
230
+
231
+ - [OWASP XSS Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html)
232
+ - [OWASP DOM XSS Prevention](https://cheatsheetseries.owasp.org/cheatsheets/DOM_based_XSS_Prevention_Cheat_Sheet.html)
233
+ - [DOMPurify Documentation](https://github.com/cure53/DOMPurify)
234
+ - [CWE-79: Improper Neutralization of Input](https://cwe.mitre.org/data/definitions/79.html)
235
+
236
+ ## Configuration
237
+
238
+ This rule can be configured in `.sunlint.json`:
239
+
240
+ ```json
241
+ {
242
+ "rules": {
243
+ "S022": {
244
+ "enabled": true,
245
+ "severity": "error",
246
+ "contexts": {
247
+ "html": { "severity": "error" },
248
+ "javascript": { "severity": "error" },
249
+ "url": { "severity": "warning" }
250
+ }
251
+ }
252
+ }
253
+ }
254
+ ```