@sun-asterisk/sunlint 1.3.2 → 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.
Files changed (59) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +5 -3
  3. package/config/rules/enhanced-rules-registry.json +144 -33
  4. package/core/analysis-orchestrator.js +167 -42
  5. package/core/auto-performance-manager.js +243 -0
  6. package/core/cli-action-handler.js +9 -1
  7. package/core/cli-program.js +19 -5
  8. package/core/constants/defaults.js +56 -0
  9. package/core/performance-optimizer.js +271 -0
  10. package/docs/FILE_LIMITS_COMPLETION_REPORT.md +151 -0
  11. package/docs/FILE_LIMITS_EXPLANATION.md +190 -0
  12. package/docs/PERFORMANCE.md +311 -0
  13. package/docs/PERFORMANCE_MIGRATION_GUIDE.md +368 -0
  14. package/docs/PERFORMANCE_OPTIMIZATION_PLAN.md +255 -0
  15. package/docs/QUICK_FILE_LIMITS.md +64 -0
  16. package/docs/SIMPLIFIED_USAGE_GUIDE.md +208 -0
  17. package/engines/heuristic-engine.js +182 -5
  18. package/package.json +2 -1
  19. package/rules/common/C048_no_bypass_architectural_layers/analyzer.js +180 -0
  20. package/rules/common/C048_no_bypass_architectural_layers/config.json +50 -0
  21. package/rules/common/C048_no_bypass_architectural_layers/symbol-based-analyzer.js +235 -0
  22. package/rules/common/C052_parsing_or_data_transformation/analyzer.js +180 -0
  23. package/rules/common/C052_parsing_or_data_transformation/config.json +50 -0
  24. package/rules/common/C052_parsing_or_data_transformation/symbol-based-analyzer.js +132 -0
  25. package/rules/index.js +2 -0
  26. package/rules/security/S017_use_parameterized_queries/README.md +128 -0
  27. package/rules/security/S017_use_parameterized_queries/analyzer.js +286 -0
  28. package/rules/security/S017_use_parameterized_queries/config.json +109 -0
  29. package/rules/security/S017_use_parameterized_queries/regex-based-analyzer.js +541 -0
  30. package/rules/security/S017_use_parameterized_queries/symbol-based-analyzer.js +777 -0
  31. package/rules/security/S031_secure_session_cookies/README.md +127 -0
  32. package/rules/security/S031_secure_session_cookies/analyzer.js +245 -0
  33. package/rules/security/S031_secure_session_cookies/config.json +86 -0
  34. package/rules/security/S031_secure_session_cookies/regex-based-analyzer.js +196 -0
  35. package/rules/security/S031_secure_session_cookies/symbol-based-analyzer.js +1084 -0
  36. package/rules/security/S032_httponly_session_cookies/FRAMEWORK_SUPPORT.md +209 -0
  37. package/rules/security/S032_httponly_session_cookies/README.md +184 -0
  38. package/rules/security/S032_httponly_session_cookies/analyzer.js +282 -0
  39. package/rules/security/S032_httponly_session_cookies/config.json +96 -0
  40. package/rules/security/S032_httponly_session_cookies/regex-based-analyzer.js +715 -0
  41. package/rules/security/S032_httponly_session_cookies/symbol-based-analyzer.js +1348 -0
  42. package/rules/security/S033_samesite_session_cookies/README.md +227 -0
  43. package/rules/security/S033_samesite_session_cookies/analyzer.js +242 -0
  44. package/rules/security/S033_samesite_session_cookies/config.json +87 -0
  45. package/rules/security/S033_samesite_session_cookies/regex-based-analyzer.js +703 -0
  46. package/rules/security/S033_samesite_session_cookies/symbol-based-analyzer.js +732 -0
  47. package/rules/security/S034_host_prefix_session_cookies/README.md +204 -0
  48. package/rules/security/S034_host_prefix_session_cookies/analyzer.js +290 -0
  49. package/rules/security/S034_host_prefix_session_cookies/config.json +62 -0
  50. package/rules/security/S034_host_prefix_session_cookies/regex-based-analyzer.js +478 -0
  51. package/rules/security/S034_host_prefix_session_cookies/symbol-based-analyzer.js +277 -0
  52. package/rules/security/S035_path_session_cookies/README.md +257 -0
  53. package/rules/security/S035_path_session_cookies/analyzer.js +316 -0
  54. package/rules/security/S035_path_session_cookies/config.json +99 -0
  55. package/rules/security/S035_path_session_cookies/regex-based-analyzer.js +724 -0
  56. package/rules/security/S035_path_session_cookies/symbol-based-analyzer.js +373 -0
  57. package/scripts/batch-processing-demo.js +334 -0
  58. package/scripts/performance-test.js +541 -0
  59. package/scripts/quick-performance-test.js +108 -0
@@ -0,0 +1,204 @@
1
+ # S034: Use \_\_Host- prefix for Session Cookies
2
+
3
+ ## Overview
4
+
5
+ This rule enforces the use of `__Host-` prefix for session cookies to prevent subdomain sharing attacks. The `__Host-` prefix is a security feature that ensures cookies are only sent to the exact domain that set them.
6
+
7
+ ## Rule Details
8
+
9
+ **Rule ID**: S034
10
+ **Category**: Security
11
+ **Severity**: Warning
12
+ **Confidence**: High
13
+
14
+ ## Description
15
+
16
+ The `__Host-` prefix is a cookie security feature that:
17
+
18
+ - Prevents subdomain cookie sharing
19
+ - Requires the cookie to be secure (HTTPS only)
20
+ - Requires path to be `/` (root path)
21
+ - Prohibits the Domain attribute
22
+ - Ensures cookies are only sent to the exact domain that set them
23
+
24
+ ## Examples
25
+
26
+ ### ❌ Violations
27
+
28
+ ```javascript
29
+ // Express.js - Missing __Host- prefix for session cookie
30
+ res.cookie("sessionid", token, {
31
+ secure: true,
32
+ httpOnly: true,
33
+ });
34
+
35
+ // NestJS - Authentication cookie without __Host- prefix
36
+ @Post('login')
37
+ login(@Res() response: Response) {
38
+ response.cookie('auth_token', value, {
39
+ secure: true,
40
+ path: '/',
41
+ });
42
+ }
43
+
44
+ // Next.js - Session cookie missing __Host- prefix
45
+ export async function POST() {
46
+ const response = NextResponse.json({ success: true });
47
+ response.cookies.set('sessionid', token, {
48
+ secure: true,
49
+ httpOnly: true,
50
+ });
51
+ return response;
52
+ }
53
+
54
+ // NextAuth.js - Session token without __Host- prefix
55
+ export default NextAuth({
56
+ cookies: {
57
+ sessionToken: {
58
+ name: 'next-auth.session-token',
59
+ options: {
60
+ secure: true,
61
+ httpOnly: true,
62
+ }
63
+ }
64
+ }
65
+ });
66
+ ```
67
+
68
+ ### ✅ Correct Usage
69
+
70
+ ```javascript
71
+ // Express.js - Proper __Host- prefix for session cookie
72
+ res.cookie("__Host-sessionid", token, {
73
+ secure: true,
74
+ httpOnly: true,
75
+ path: "/",
76
+ });
77
+
78
+ // NestJS - Authentication cookie with __Host- prefix
79
+ @Post('login')
80
+ login(@Res() response: Response) {
81
+ response.cookie('__Host-auth_token', value, {
82
+ secure: true,
83
+ httpOnly: true,
84
+ path: '/',
85
+ });
86
+ }
87
+
88
+ // Next.js - Session cookie with __Host- prefix
89
+ export async function POST() {
90
+ const response = NextResponse.json({ success: true });
91
+ response.cookies.set('__Host-sessionid', token, {
92
+ secure: true,
93
+ httpOnly: true,
94
+ path: '/',
95
+ });
96
+ return response;
97
+ }
98
+
99
+ // NextAuth.js - Session token with __Host- prefix
100
+ export default NextAuth({
101
+ cookies: {
102
+ sessionToken: {
103
+ name: '__Host-next-auth.session-token',
104
+ options: {
105
+ secure: true,
106
+ httpOnly: true,
107
+ path: '/',
108
+ }
109
+ }
110
+ }
111
+ });
112
+ ```
113
+
114
+ ## \_\_Host- Prefix Requirements
115
+
116
+ When using the `__Host-` prefix, the following requirements must be met:
117
+
118
+ 1. **Secure**: Cookie must have the `Secure` attribute (HTTPS only)
119
+ 2. **Path**: Must be set to `/` (root path)
120
+ 3. **Domain**: Must NOT have a Domain attribute
121
+ 4. **Exact Domain**: Cookie will only be sent to the exact domain that set it
122
+
123
+ ## Detected Patterns
124
+
125
+ This rule detects session cookies without `__Host-` prefix in multiple frameworks:
126
+
127
+ ### Express.js
128
+
129
+ - `res.cookie()` calls with session cookie names without `__Host-` prefix
130
+ - `res.setHeader()` with `Set-Cookie` headers missing `__Host-` prefix
131
+ - Session middleware configuration with cookie names missing `__Host-` prefix
132
+ - Array of Set-Cookie headers with session cookies missing `__Host-` prefix
133
+
134
+ ### NestJS
135
+
136
+ - `@Res()` decorator response cookie methods
137
+ - `@Cookies()` decorator usage with session cookies
138
+ - Response object cookie setting methods
139
+ - NestJS session middleware configuration
140
+
141
+ ### Next.js
142
+
143
+ - `response.cookies.set()` method calls
144
+ - `cookies().set()` from next/headers
145
+ - NextAuth.js session and CSRF token configuration
146
+ - API route response cookie setting
147
+
148
+ ### NextAuth.js
149
+
150
+ - Session token configuration without `__Host-` prefix
151
+ - CSRF token configuration missing `__Host-` prefix
152
+ - Cookie configuration in NextAuth providers
153
+
154
+ ## Session Cookie Detection
155
+
156
+ The rule identifies session cookies based on common naming patterns:
157
+
158
+ - `session`, `sessionid`, `session_id`
159
+ - `sid`, `connect.sid`
160
+ - `auth`, `auth_token`, `authentication`
161
+ - `jwt`, `token`
162
+ - `csrf`, `csrf_token`, `xsrf`
163
+ - `login`, `user`, `userid`, `user_id`
164
+ - `sessionToken`, `csrfToken` (NextAuth specific)
165
+
166
+ ## Configuration
167
+
168
+ The rule uses regex-based analysis for comprehensive framework support:
169
+
170
+ - **Regex-based**: Pattern matching for framework-specific cookie patterns
171
+ - **Framework Support**: Express.js, NestJS, Next.js, NextAuth.js
172
+
173
+ ## Security Impact
174
+
175
+ **Without \_\_Host- prefix:**
176
+
177
+ - Subdomain cookie sharing vulnerabilities
178
+ - Session fixation attacks from subdomains
179
+ - Cross-subdomain session hijacking
180
+
181
+ **With \_\_Host- prefix:**
182
+
183
+ - Cookies isolated to exact domain
184
+ - Prevention of subdomain attacks
185
+ - Enhanced session security
186
+
187
+ ## Compatibility
188
+
189
+ - **Node.js**: All versions
190
+ - **Frameworks**: Express.js, NestJS, Next.js, NextAuth.js
191
+ - **Browsers**: Modern browsers supporting \_\_Host- prefix
192
+ - **Languages**: JavaScript, TypeScript
193
+
194
+ ## References
195
+
196
+ - [MDN: \_\_Host- prefix](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#__Host-)
197
+ - [RFC Draft: Cookie Prefixes](https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00)
198
+ - [OWASP: Secure Cookie Attribute](https://owasp.org/www-community/controls/SecureCookieAttribute)
199
+
200
+ ## Related Rules
201
+
202
+ - **S031**: Set Secure attribute for Session Cookies
203
+ - **S032**: Set HttpOnly attribute for Session Cookies
204
+ - **S033**: Set SameSite attribute for Session Cookies
@@ -0,0 +1,290 @@
1
+ /**
2
+ * S034 Main Analyzer - Use __Host- prefix for Session Cookies
3
+ * Primary: Symbol-based analysis (when available)
4
+ * Fallback: Regex-based for all other cases
5
+ * Command: node cli.js --rule=S034 --input=examples/rule-test-fixtures/rules/S034_host_prefix_session_cookies --engine=heuristic
6
+ */
7
+
8
+ const S034SymbolBasedAnalyzer = require("./symbol-based-analyzer.js");
9
+ const S034RegexBasedAnalyzer = require("./regex-based-analyzer.js");
10
+
11
+ class S034Analyzer {
12
+ constructor(options = {}) {
13
+ if (process.env.SUNLINT_DEBUG) {
14
+ console.log(`🔧 [S034] Constructor called with options:`, !!options);
15
+ console.log(
16
+ `🔧 [S034] Options type:`,
17
+ typeof options,
18
+ Object.keys(options || {})
19
+ );
20
+ }
21
+
22
+ this.ruleId = "S034";
23
+ this.ruleName = "Use __Host- prefix for Session Cookies";
24
+ this.description =
25
+ "Use __Host- prefix for Session Cookies to prevent subdomain sharing. The __Host- prefix ensures cookies are only sent to the exact domain that set them, preventing subdomain cookie sharing attacks.";
26
+ this.semanticEngine = options.semanticEngine || null;
27
+ this.verbose = options.verbose || false;
28
+
29
+ // Configuration - Use symbol-based as primary, regex for additional coverage
30
+ this.config = {
31
+ useSymbolBased: true, // Primary approach
32
+ fallbackToRegex: true, // Additional coverage
33
+ regexBasedOnly: false, // Can be set to true for pure mode
34
+ };
35
+
36
+ // Initialize analyzers
37
+ try {
38
+ this.symbolAnalyzer = new S034SymbolBasedAnalyzer(this.semanticEngine);
39
+ if (process.env.SUNLINT_DEBUG) {
40
+ console.log(`🔧 [S034] Symbol analyzer created successfully`);
41
+ }
42
+ } catch (error) {
43
+ console.error(`🔧 [S034] Error creating symbol analyzer:`, error);
44
+ }
45
+
46
+ try {
47
+ this.regexAnalyzer = new S034RegexBasedAnalyzer(this.semanticEngine);
48
+ if (process.env.SUNLINT_DEBUG) {
49
+ console.log(`🔧 [S034] Regex analyzer created successfully`);
50
+ }
51
+ } catch (error) {
52
+ console.error(`🔧 [S034] Error creating regex analyzer:`, error);
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Initialize analyzer with semantic engine
58
+ */
59
+ async initialize(semanticEngine) {
60
+ this.semanticEngine = semanticEngine;
61
+
62
+ if (process.env.SUNLINT_DEBUG) {
63
+ console.log(`🔧 [S034] Main analyzer initializing...`);
64
+ }
65
+
66
+ // Initialize both analyzers
67
+ if (this.symbolAnalyzer) {
68
+ await this.symbolAnalyzer.initialize?.(semanticEngine);
69
+ }
70
+ if (this.regexAnalyzer) {
71
+ await this.regexAnalyzer.initialize?.(semanticEngine);
72
+ }
73
+
74
+ // Clean up if needed
75
+ if (this.regexAnalyzer) {
76
+ this.regexAnalyzer.cleanup?.();
77
+ }
78
+
79
+ if (process.env.SUNLINT_DEBUG) {
80
+ console.log(`🔧 [S034] Main analyzer initialized successfully`);
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Single file analysis method for testing
86
+ */
87
+ analyzeSingle(filePath, options = {}) {
88
+ if (process.env.SUNLINT_DEBUG) {
89
+ console.log(`🔍 [S034] analyzeSingle() called for: ${filePath}`);
90
+ }
91
+
92
+ // Return result using same format as analyze method
93
+ return this.analyze([filePath], "typescript", options);
94
+ }
95
+
96
+ async analyze(files, language, options = {}) {
97
+ if (process.env.SUNLINT_DEBUG) {
98
+ console.log(
99
+ `🔧 [S034] analyze() method called with ${files.length} files, language: ${language}`
100
+ );
101
+ }
102
+
103
+ const violations = [];
104
+
105
+ for (const filePath of files) {
106
+ try {
107
+ if (process.env.SUNLINT_DEBUG) {
108
+ console.log(`🔧 [S034] Processing file: ${filePath}`);
109
+ }
110
+
111
+ const fileViolations = await this.analyzeFile(filePath, options);
112
+ violations.push(...fileViolations);
113
+
114
+ if (process.env.SUNLINT_DEBUG) {
115
+ console.log(
116
+ `🔧 [S034] File ${filePath}: Found ${fileViolations.length} violations`
117
+ );
118
+ }
119
+ } catch (error) {
120
+ console.warn(
121
+ `⚠ [S034] Analysis failed for ${filePath}:`,
122
+ error.message
123
+ );
124
+ }
125
+ }
126
+
127
+ if (process.env.SUNLINT_DEBUG) {
128
+ console.log(`🔧 [S034] Total violations found: ${violations.length}`);
129
+ }
130
+
131
+ return violations;
132
+ }
133
+
134
+ async analyzeFile(filePath, options = {}) {
135
+ if (process.env.SUNLINT_DEBUG) {
136
+ console.log(`🔍 [S034] analyzeFile() called for: ${filePath}`);
137
+ }
138
+
139
+ // Create a Map to track unique violations and prevent duplicates
140
+ const violationMap = new Map();
141
+ const lineToViolationMap = new Map(); // Track which lines already have violations
142
+
143
+ // 1. Try Symbol-based analysis first (primary)
144
+ if (
145
+ this.config.useSymbolBased &&
146
+ this.semanticEngine?.project &&
147
+ this.semanticEngine?.initialized
148
+ ) {
149
+ try {
150
+ if (process.env.SUNLINT_DEBUG) {
151
+ console.log(`🔧 [S034] Trying symbol-based analysis...`);
152
+ }
153
+ const sourceFile = this.semanticEngine.project.getSourceFile(filePath);
154
+ if (sourceFile) {
155
+ if (process.env.SUNLINT_DEBUG) {
156
+ console.log(`🔧 [S034] Source file found, analyzing...`);
157
+ }
158
+ const symbolViolations = await this.symbolAnalyzer.analyze(
159
+ sourceFile,
160
+ filePath
161
+ );
162
+
163
+ // Add symbol violations first (higher priority)
164
+ symbolViolations.forEach((violation) => {
165
+ // Extract cookie name from message for better deduplication
166
+ const cookieNameMatch =
167
+ violation.message.match(
168
+ /(?:Session (?:cookie|middleware cookie name)|Set-Cookie.*?|NextAuth.*?) "([^"]+)"/
169
+ ) ||
170
+ violation.message.match(
171
+ /Insecure session cookie:.*?(?:Session cookie|NextAuth.*?) "([^"]+)"/
172
+ );
173
+ const cookieName = cookieNameMatch ? cookieNameMatch[1] : "unknown";
174
+
175
+ // Use specific key including column for exact match
176
+ const specificKey = `${violation.line}:${
177
+ violation.column || 1
178
+ }:${cookieName}`;
179
+ const lineKey = `${violation.line}:${cookieName}`;
180
+
181
+ if (!violationMap.has(specificKey)) {
182
+ violationMap.set(specificKey, {
183
+ ...violation,
184
+ source: "symbol", // Track source for debugging
185
+ });
186
+
187
+ // Also track by line for regex deduplication
188
+ lineToViolationMap.set(lineKey, specificKey);
189
+ }
190
+ });
191
+
192
+ if (process.env.SUNLINT_DEBUG) {
193
+ console.log(
194
+ `🔧 [S034] Symbol analysis completed: ${symbolViolations.length} violations`
195
+ );
196
+ }
197
+ } else {
198
+ if (process.env.SUNLINT_DEBUG) {
199
+ console.log(`🔧 [S034] Source file not found, falling back...`);
200
+ }
201
+ }
202
+ } catch (error) {
203
+ console.warn(`⚠ [S034] Symbol analysis failed:`, error.message);
204
+ }
205
+ }
206
+
207
+ // 2. Try Regex-based analysis (fallback or additional)
208
+ if (this.config.fallbackToRegex || this.config.regexBasedOnly) {
209
+ try {
210
+ if (process.env.SUNLINT_DEBUG) {
211
+ console.log(`🔧 [S034] Trying regex-based analysis...`);
212
+ }
213
+ const regexViolations = await this.regexAnalyzer.analyze(filePath);
214
+
215
+ // Add regex violations only if not already covered by symbol analysis
216
+ regexViolations.forEach((violation) => {
217
+ // Extract cookie name from message for better deduplication
218
+ const cookieNameMatch =
219
+ violation.message.match(
220
+ /(?:Session (?:cookie|middleware cookie name)|Set-Cookie.*?|NextAuth.*?) "([^"]+)"/
221
+ ) ||
222
+ violation.message.match(
223
+ /Insecure session cookie:.*?(?:Session cookie|NextAuth.*?) "([^"]+)"/
224
+ );
225
+ const cookieName = cookieNameMatch ? cookieNameMatch[1] : "unknown";
226
+
227
+ // Check if this line+cookie already has a violation from symbol analyzer
228
+ const lineKey = `${violation.line}:${cookieName}`;
229
+
230
+ if (!lineToViolationMap.has(lineKey)) {
231
+ // No symbol violation for this line+cookie, add regex violation
232
+ const specificKey = `${violation.line}:${
233
+ violation.column || 1
234
+ }:${cookieName}:regex`;
235
+
236
+ if (!violationMap.has(specificKey)) {
237
+ violationMap.set(specificKey, {
238
+ ...violation,
239
+ source: "regex", // Track source for debugging
240
+ });
241
+ }
242
+ } else if (process.env.SUNLINT_DEBUG) {
243
+ console.log(
244
+ `🔧 [S034] Skipping duplicate regex violation at ${lineKey} (already covered by symbol)`
245
+ );
246
+ }
247
+ });
248
+
249
+ if (process.env.SUNLINT_DEBUG) {
250
+ console.log(
251
+ `🔧 [S034] Regex analysis completed: ${regexViolations.length} violations`
252
+ );
253
+ }
254
+ } catch (error) {
255
+ console.warn(`⚠ [S034] Regex analysis failed:`, error.message);
256
+ }
257
+ }
258
+
259
+ // Convert Map values to array and add filePath to each violation
260
+ const finalViolations = Array.from(violationMap.values()).map(
261
+ (violation) => ({
262
+ ...violation,
263
+ filePath: filePath,
264
+ file: filePath, // Also add 'file' for compatibility
265
+ })
266
+ );
267
+
268
+ if (process.env.SUNLINT_DEBUG) {
269
+ console.log(
270
+ `🔧 [S034] File analysis completed: ${finalViolations.length} unique violations`
271
+ );
272
+ }
273
+
274
+ return finalViolations;
275
+ }
276
+
277
+ /**
278
+ * Clean up resources
279
+ */
280
+ cleanup() {
281
+ if (this.symbolAnalyzer?.cleanup) {
282
+ this.symbolAnalyzer.cleanup();
283
+ }
284
+ if (this.regexAnalyzer?.cleanup) {
285
+ this.regexAnalyzer.cleanup();
286
+ }
287
+ }
288
+ }
289
+
290
+ module.exports = S034Analyzer;
@@ -0,0 +1,62 @@
1
+ {
2
+ "id": "S034",
3
+ "name": "Use __Host- prefix for Session Cookies",
4
+ "description": "Use __Host- prefix for Session Cookies to prevent subdomain sharing. The __Host- prefix ensures cookies are only sent to the exact domain that set them, preventing subdomain cookie sharing attacks.",
5
+ "category": "security",
6
+ "severity": "warning",
7
+ "confidence": "high",
8
+ "tags": ["cookie", "security", "session", "subdomain", "host-prefix"],
9
+ "languages": ["javascript", "typescript"],
10
+ "patterns": {
11
+ "cookieNamePatterns": [
12
+ "session",
13
+ "sessionid",
14
+ "session_id",
15
+ "sid",
16
+ "connect.sid",
17
+ "auth",
18
+ "auth_token",
19
+ "authentication",
20
+ "jwt",
21
+ "token",
22
+ "csrf",
23
+ "csrf_token",
24
+ "xsrf",
25
+ "login",
26
+ "user",
27
+ "userid",
28
+ "user_id"
29
+ ],
30
+ "hostPrefixPattern": "^__Host-",
31
+ "violationPatterns": [
32
+ "res\\.cookie\\s*\\(\\s*['\"`](?!__Host-)",
33
+ "Set-Cookie:\\s*(?!__Host-)",
34
+ "cookie:\\s*{[^}]*name\\s*:\\s*['\"`](?!__Host-)"
35
+ ]
36
+ },
37
+ "validation": {
38
+ "hostPrefixRequirements": {
39
+ "secure": true,
40
+ "path": "/",
41
+ "domain": null,
42
+ "description": "__Host- prefix requires Secure=true, Path=/, and no Domain attribute"
43
+ }
44
+ },
45
+ "examples": {
46
+ "violation": [
47
+ "res.cookie('sessionid', token, { secure: true, httpOnly: true })",
48
+ "res.cookie('auth_token', value, { secure: true, path: '/' })",
49
+ "res.setHeader('Set-Cookie', 'session=value; Secure; HttpOnly')"
50
+ ],
51
+ "clean": [
52
+ "res.cookie('__Host-sessionid', token, { secure: true, httpOnly: true, path: '/' })",
53
+ "res.cookie('__Host-auth_token', value, { secure: true, path: '/', domain: undefined })",
54
+ "res.setHeader('Set-Cookie', '__Host-session=value; Secure; HttpOnly; Path=/')"
55
+ ]
56
+ },
57
+ "references": [
58
+ "https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#__Host-",
59
+ "https://tools.ietf.org/html/draft-ietf-httpbis-cookie-prefixes-00",
60
+ "https://owasp.org/www-community/controls/SecureCookieAttribute"
61
+ ]
62
+ }