@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.
- package/CHANGELOG.md +38 -0
- package/README.md +5 -3
- package/config/rules/enhanced-rules-registry.json +144 -33
- 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/performance-optimizer.js +271 -0
- 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 +182 -5
- package/package.json +2 -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 +2 -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/scripts/batch-processing-demo.js +334 -0
- package/scripts/performance-test.js +541 -0
- package/scripts/quick-performance-test.js +108 -0
|
@@ -0,0 +1,478 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S034 Regex-based Analyzer - Use __Host- prefix for Session Cookies
|
|
3
|
+
* Fallback analyzer for pattern-based detection
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const fs = require("fs");
|
|
7
|
+
|
|
8
|
+
class S034RegexBasedAnalyzer {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.ruleId = "S034";
|
|
11
|
+
this.ruleName = "Use __Host- prefix for Session Cookies";
|
|
12
|
+
this.description =
|
|
13
|
+
"Use __Host- prefix for Session Cookies to prevent subdomain sharing";
|
|
14
|
+
this.category = "security";
|
|
15
|
+
this.verbose = process.env.SUNLINT_DEBUG === "true";
|
|
16
|
+
|
|
17
|
+
// Enhanced regex patterns for framework detection
|
|
18
|
+
this.patterns = {
|
|
19
|
+
// Traditional Express.js patterns
|
|
20
|
+
cookieCall: /res\.cookie\s*\(\s*['"`]([^'"`]+)['"`]/g,
|
|
21
|
+
setCookieHeader:
|
|
22
|
+
/res\.setHeader\s*\(\s*['"`]Set-Cookie['"`]\s*,\s*['"`]([^'"`=]+)=/gi,
|
|
23
|
+
setCookieArray:
|
|
24
|
+
/res\.setHeader\s*\(\s*['"`]Set-Cookie['"`]\s*,\s*\[([^\]]+)\]/gi,
|
|
25
|
+
sessionMiddleware:
|
|
26
|
+
/session\s*\(\s*\{[^}]*name\s*:\s*['"`]([^'"`]+)['"`]/g,
|
|
27
|
+
|
|
28
|
+
// NestJS patterns
|
|
29
|
+
nestJSCookieSet:
|
|
30
|
+
/@Res\(\)\s+\w+:\s*Response[\s\S]*?\.cookie\s*\(\s*['"`]([^'"`]+)['"`]/g,
|
|
31
|
+
nestJSCookieDecorator: /@Cookies\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g,
|
|
32
|
+
nestJSResponseCookie: /response\.cookie\s*\(\s*['"`]([^'"`]+)['"`]/g,
|
|
33
|
+
|
|
34
|
+
// Next.js patterns
|
|
35
|
+
nextJSResponseCookies:
|
|
36
|
+
/response\.cookies\.set\s*\(\s*['"`]([^'"`]+)['"`]/g,
|
|
37
|
+
nextJSCookiesFunction: /cookies\(\)\.set\s*\(\s*['"`]([^'"`]+)['"`]/g,
|
|
38
|
+
nextJSCookieStore: /cookieStore\.set\s*\(\s*['"`]([^'"`]+)['"`]/g,
|
|
39
|
+
|
|
40
|
+
// Nuxt.js patterns
|
|
41
|
+
nuxtCookieSet: /useCookie\s*\(\s*['"`]([^'"`]+)['"`]/g,
|
|
42
|
+
nuxtServerCookie: /setCookie\s*\(\s*\w+\s*,\s*['"`]([^'"`]+)['"`]/g,
|
|
43
|
+
nuxtH3Cookie: /setCookie\s*\(\s*event\s*,\s*['"`]([^'"`]+)['"`]/g,
|
|
44
|
+
|
|
45
|
+
// Session cookie names (enhanced)
|
|
46
|
+
sessionCookieNames:
|
|
47
|
+
/^(session|sessionid|session_id|sid|connect\.sid|auth|auth_token|authentication|jwt|token|csrf|csrf_token|xsrf|login|user|userid|user_id|api_session|admin_session|app_auth|edge_session|server_session|refresh_token|next-auth\.session-token|next-auth\.csrf-token|custom-session-token)$/i,
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
this.violations = [];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async initialize(semanticEngine) {
|
|
54
|
+
this.semanticEngine = semanticEngine;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async analyze(filePath) {
|
|
58
|
+
if (this.verbose) {
|
|
59
|
+
console.log(
|
|
60
|
+
`🔍 [${this.ruleId}] Regex analysis starting for: ${filePath}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.violations = [];
|
|
65
|
+
|
|
66
|
+
try {
|
|
67
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
68
|
+
const lines = content.split("\n");
|
|
69
|
+
|
|
70
|
+
// Framework detection
|
|
71
|
+
const framework = this.detectFramework(content);
|
|
72
|
+
|
|
73
|
+
if (this.verbose) {
|
|
74
|
+
console.log(`🔍 [${this.ruleId}] Detected framework: ${framework}`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Traditional Express.js patterns
|
|
78
|
+
this.checkCookieCalls(content, lines, filePath);
|
|
79
|
+
this.checkSetCookieHeaders(content, lines, filePath);
|
|
80
|
+
this.checkSessionMiddleware(content, lines, filePath);
|
|
81
|
+
|
|
82
|
+
// Framework-specific patterns
|
|
83
|
+
this.checkNestJSPatterns(content, lines, filePath);
|
|
84
|
+
this.checkNextJSPatterns(content, lines, filePath);
|
|
85
|
+
this.checkNuxtJSPatterns(content, lines, filePath);
|
|
86
|
+
this.analyzeNextAuthConfig(content, lines, filePath);
|
|
87
|
+
} catch (error) {
|
|
88
|
+
console.warn(`⚠ [${this.ruleId}] Regex analysis error:`, error.message);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (this.verbose) {
|
|
92
|
+
console.log(
|
|
93
|
+
`🔍 [${this.ruleId}] Regex analysis completed: ${this.violations.length} violations`
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
return this.violations;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
detectFramework(content) {
|
|
101
|
+
if (
|
|
102
|
+
content.includes("@nestjs") ||
|
|
103
|
+
content.includes("@Res()") ||
|
|
104
|
+
content.includes("@Cookies")
|
|
105
|
+
) {
|
|
106
|
+
return "NestJS";
|
|
107
|
+
}
|
|
108
|
+
if (
|
|
109
|
+
content.includes("next/") ||
|
|
110
|
+
content.includes("NextRequest") ||
|
|
111
|
+
content.includes("NextResponse")
|
|
112
|
+
) {
|
|
113
|
+
return "Next.js";
|
|
114
|
+
}
|
|
115
|
+
if (
|
|
116
|
+
content.includes("#nuxt") ||
|
|
117
|
+
content.includes("useCookie") ||
|
|
118
|
+
content.includes("setCookie")
|
|
119
|
+
) {
|
|
120
|
+
return "Nuxt.js";
|
|
121
|
+
}
|
|
122
|
+
return "Express.js";
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
checkCookieCalls(content, lines, filePath) {
|
|
126
|
+
let match;
|
|
127
|
+
this.patterns.cookieCall.lastIndex = 0;
|
|
128
|
+
|
|
129
|
+
while ((match = this.patterns.cookieCall.exec(content)) !== null) {
|
|
130
|
+
const cookieName = match[1];
|
|
131
|
+
|
|
132
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
133
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
134
|
+
this.addViolation(
|
|
135
|
+
lineNumber,
|
|
136
|
+
1,
|
|
137
|
+
`Insecure session cookie: Session cookie "${cookieName}" (Express.js) missing __Host- prefix`,
|
|
138
|
+
filePath
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
checkSetCookieHeaders(content, lines, filePath) {
|
|
145
|
+
// Check direct Set-Cookie headers
|
|
146
|
+
let match;
|
|
147
|
+
this.patterns.setCookieHeader.lastIndex = 0;
|
|
148
|
+
|
|
149
|
+
while ((match = this.patterns.setCookieHeader.exec(content)) !== null) {
|
|
150
|
+
const cookieName = match[1];
|
|
151
|
+
|
|
152
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
153
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
154
|
+
this.addViolation(
|
|
155
|
+
lineNumber,
|
|
156
|
+
1,
|
|
157
|
+
`Insecure session cookie: Session cookie "${cookieName}" in Set-Cookie header missing __Host- prefix`,
|
|
158
|
+
filePath
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
// Check Set-Cookie arrays
|
|
164
|
+
this.patterns.setCookieArray.lastIndex = 0;
|
|
165
|
+
|
|
166
|
+
while ((match = this.patterns.setCookieArray.exec(content)) !== null) {
|
|
167
|
+
const arrayContent = match[1];
|
|
168
|
+
const cookieMatches = arrayContent.match(/['"`]([^'"`=]+)=/g);
|
|
169
|
+
|
|
170
|
+
if (cookieMatches) {
|
|
171
|
+
cookieMatches.forEach((cookieMatch) => {
|
|
172
|
+
const cookieName = cookieMatch.replace(/['"`]/g, "").replace("=", "");
|
|
173
|
+
|
|
174
|
+
if (
|
|
175
|
+
this.isSessionCookie(cookieName) &&
|
|
176
|
+
!this.hasHostPrefix(cookieName)
|
|
177
|
+
) {
|
|
178
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
179
|
+
this.addViolation(
|
|
180
|
+
lineNumber,
|
|
181
|
+
1,
|
|
182
|
+
`Insecure session cookie: Session cookie "${cookieName}" in Set-Cookie array missing __Host- prefix`,
|
|
183
|
+
filePath
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
checkSessionMiddleware(content, lines, filePath) {
|
|
192
|
+
let match;
|
|
193
|
+
this.patterns.sessionMiddleware.lastIndex = 0;
|
|
194
|
+
|
|
195
|
+
while ((match = this.patterns.sessionMiddleware.exec(content)) !== null) {
|
|
196
|
+
const cookieName = match[1];
|
|
197
|
+
|
|
198
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
199
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
200
|
+
this.addViolation(
|
|
201
|
+
lineNumber,
|
|
202
|
+
1,
|
|
203
|
+
`Insecure session cookie: Session middleware cookie name "${cookieName}" missing __Host- prefix`,
|
|
204
|
+
filePath
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Framework-specific analysis methods
|
|
211
|
+
checkNestJSPatterns(content, lines, filePath) {
|
|
212
|
+
// NestJS @Res() decorator with cookie setting
|
|
213
|
+
let match;
|
|
214
|
+
this.patterns.nestJSCookieSet.lastIndex = 0;
|
|
215
|
+
|
|
216
|
+
while ((match = this.patterns.nestJSCookieSet.exec(content)) !== null) {
|
|
217
|
+
const cookieName = match[1];
|
|
218
|
+
|
|
219
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
220
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
221
|
+
this.addViolation(
|
|
222
|
+
lineNumber,
|
|
223
|
+
1,
|
|
224
|
+
`Insecure session cookie: Session cookie "${cookieName}" (NestJS) missing __Host- prefix`,
|
|
225
|
+
filePath
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// NestJS response.cookie() calls
|
|
231
|
+
this.patterns.nestJSResponseCookie.lastIndex = 0;
|
|
232
|
+
|
|
233
|
+
while (
|
|
234
|
+
(match = this.patterns.nestJSResponseCookie.exec(content)) !== null
|
|
235
|
+
) {
|
|
236
|
+
const cookieName = match[1];
|
|
237
|
+
|
|
238
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
239
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
240
|
+
this.addViolation(
|
|
241
|
+
lineNumber,
|
|
242
|
+
1,
|
|
243
|
+
`Insecure session cookie: Session cookie "${cookieName}" (NestJS) missing __Host- prefix`,
|
|
244
|
+
filePath
|
|
245
|
+
);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// NestJS @Cookies decorator
|
|
250
|
+
this.patterns.nestJSCookieDecorator.lastIndex = 0;
|
|
251
|
+
|
|
252
|
+
while (
|
|
253
|
+
(match = this.patterns.nestJSCookieDecorator.exec(content)) !== null
|
|
254
|
+
) {
|
|
255
|
+
const cookieName = match[1];
|
|
256
|
+
|
|
257
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
258
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
259
|
+
this.addViolation(
|
|
260
|
+
lineNumber,
|
|
261
|
+
1,
|
|
262
|
+
`Insecure session cookie: Session cookie "${cookieName}" (NestJS) missing __Host- prefix`,
|
|
263
|
+
filePath
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
checkNextJSPatterns(content, lines, filePath) {
|
|
270
|
+
// Next.js response.cookies.set()
|
|
271
|
+
let match;
|
|
272
|
+
this.patterns.nextJSResponseCookies.lastIndex = 0;
|
|
273
|
+
|
|
274
|
+
while (
|
|
275
|
+
(match = this.patterns.nextJSResponseCookies.exec(content)) !== null
|
|
276
|
+
) {
|
|
277
|
+
const cookieName = match[1];
|
|
278
|
+
|
|
279
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
280
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
281
|
+
this.addViolation(
|
|
282
|
+
lineNumber,
|
|
283
|
+
1,
|
|
284
|
+
`Insecure session cookie: Session cookie "${cookieName}" (Next.js) missing __Host- prefix`,
|
|
285
|
+
filePath
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Next.js cookies().set()
|
|
291
|
+
this.patterns.nextJSCookiesFunction.lastIndex = 0;
|
|
292
|
+
|
|
293
|
+
while (
|
|
294
|
+
(match = this.patterns.nextJSCookiesFunction.exec(content)) !== null
|
|
295
|
+
) {
|
|
296
|
+
const cookieName = match[1];
|
|
297
|
+
|
|
298
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
299
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
300
|
+
this.addViolation(
|
|
301
|
+
lineNumber,
|
|
302
|
+
1,
|
|
303
|
+
`Insecure session cookie: Session cookie "${cookieName}" (Next.js) missing __Host- prefix`,
|
|
304
|
+
filePath
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Next.js cookieStore.set()
|
|
310
|
+
this.patterns.nextJSCookieStore.lastIndex = 0;
|
|
311
|
+
|
|
312
|
+
while ((match = this.patterns.nextJSCookieStore.exec(content)) !== null) {
|
|
313
|
+
const cookieName = match[1];
|
|
314
|
+
|
|
315
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
316
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
317
|
+
this.addViolation(
|
|
318
|
+
lineNumber,
|
|
319
|
+
1,
|
|
320
|
+
`Insecure session cookie: Session cookie "${cookieName}" (Next.js) missing __Host- prefix`,
|
|
321
|
+
filePath
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
checkNuxtJSPatterns(content, lines, filePath) {
|
|
328
|
+
// Nuxt.js useCookie()
|
|
329
|
+
let match;
|
|
330
|
+
this.patterns.nuxtCookieSet.lastIndex = 0;
|
|
331
|
+
|
|
332
|
+
while ((match = this.patterns.nuxtCookieSet.exec(content)) !== null) {
|
|
333
|
+
const cookieName = match[1];
|
|
334
|
+
|
|
335
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
336
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
337
|
+
this.addViolation(
|
|
338
|
+
lineNumber,
|
|
339
|
+
1,
|
|
340
|
+
`Insecure session cookie: Session cookie "${cookieName}" (Nuxt.js) missing __Host- prefix`,
|
|
341
|
+
filePath
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// Nuxt.js setCookie() server
|
|
347
|
+
this.patterns.nuxtServerCookie.lastIndex = 0;
|
|
348
|
+
|
|
349
|
+
while ((match = this.patterns.nuxtServerCookie.exec(content)) !== null) {
|
|
350
|
+
const cookieName = match[1];
|
|
351
|
+
|
|
352
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
353
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
354
|
+
this.addViolation(
|
|
355
|
+
lineNumber,
|
|
356
|
+
1,
|
|
357
|
+
`Insecure session cookie: Session cookie "${cookieName}" (Nuxt.js) missing __Host- prefix`,
|
|
358
|
+
filePath
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
// Nuxt.js H3 setCookie()
|
|
364
|
+
this.patterns.nuxtH3Cookie.lastIndex = 0;
|
|
365
|
+
|
|
366
|
+
while ((match = this.patterns.nuxtH3Cookie.exec(content)) !== null) {
|
|
367
|
+
const cookieName = match[1];
|
|
368
|
+
|
|
369
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
370
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
371
|
+
this.addViolation(
|
|
372
|
+
lineNumber,
|
|
373
|
+
1,
|
|
374
|
+
`Insecure session cookie: Session cookie "${cookieName}" (Nuxt.js) missing __Host- prefix`,
|
|
375
|
+
filePath
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
analyzeNextAuthConfig(content, lines, filePath) {
|
|
382
|
+
const violations = [];
|
|
383
|
+
|
|
384
|
+
// Simple approach: find NextAuth cookie configurations directly
|
|
385
|
+
// Pattern 1: sessionToken configurations
|
|
386
|
+
const sessionTokenPattern =
|
|
387
|
+
/sessionToken\s*:\s*\{[^}]*name\s*:\s*['"`]([^'"`]+)['"`]/gi;
|
|
388
|
+
let match;
|
|
389
|
+
|
|
390
|
+
while ((match = sessionTokenPattern.exec(content)) !== null) {
|
|
391
|
+
const cookieName = match[1];
|
|
392
|
+
|
|
393
|
+
if (this.verbose) {
|
|
394
|
+
console.log(
|
|
395
|
+
`🔍 [${this.ruleId}] Regex: sessionToken Pattern match - name: "${cookieName}"`
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
400
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
401
|
+
this.addViolation(
|
|
402
|
+
lineNumber,
|
|
403
|
+
1,
|
|
404
|
+
`Insecure session cookie: NextAuth "sessionToken" cookie "${cookieName}" missing __Host- prefix`,
|
|
405
|
+
filePath
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// Pattern 2: csrfToken configurations
|
|
411
|
+
const csrfTokenPattern =
|
|
412
|
+
/csrfToken\s*:\s*\{[^}]*name\s*:\s*['"`]([^'"`]+)['"`]/gi;
|
|
413
|
+
|
|
414
|
+
while ((match = csrfTokenPattern.exec(content)) !== null) {
|
|
415
|
+
const cookieName = match[1];
|
|
416
|
+
|
|
417
|
+
if (this.verbose) {
|
|
418
|
+
console.log(
|
|
419
|
+
`🔍 [${this.ruleId}] Regex: csrfToken Pattern match - name: "${cookieName}"`
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if (this.isSessionCookie(cookieName) && !this.hasHostPrefix(cookieName)) {
|
|
424
|
+
const lineNumber = this.getLineNumber(content, match.index);
|
|
425
|
+
this.addViolation(
|
|
426
|
+
lineNumber,
|
|
427
|
+
1,
|
|
428
|
+
`Insecure session cookie: NextAuth "csrfToken" cookie "${cookieName}" missing __Host- prefix`,
|
|
429
|
+
filePath
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
return violations;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
isSessionCookie(cookieName) {
|
|
438
|
+
return this.patterns.sessionCookieNames.test(cookieName);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
hasHostPrefix(cookieName) {
|
|
442
|
+
return cookieName.startsWith("__Host-");
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
getLineNumber(content, position) {
|
|
446
|
+
const beforePosition = content.substring(0, position);
|
|
447
|
+
return beforePosition.split("\n").length;
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
addViolation(line, column, message, filePath) {
|
|
451
|
+
if (this.verbose) {
|
|
452
|
+
console.log(
|
|
453
|
+
`🔍 [${
|
|
454
|
+
this.ruleId
|
|
455
|
+
}] Regex violation at line ${line}, column ${column}: ${message.substring(
|
|
456
|
+
0,
|
|
457
|
+
50
|
|
458
|
+
)}...`
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
this.violations.push({
|
|
463
|
+
rule: this.ruleId,
|
|
464
|
+
source: filePath,
|
|
465
|
+
category: this.category,
|
|
466
|
+
line: line,
|
|
467
|
+
column: column,
|
|
468
|
+
message: message,
|
|
469
|
+
severity: "warning",
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
cleanup() {
|
|
474
|
+
this.violations = [];
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
module.exports = S034RegexBasedAnalyzer;
|