supasec 1.0.3 → 1.0.5

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 (117) hide show
  1. package/Feature-List.md +233 -0
  2. package/README.md +53 -12
  3. package/dist/cli.js +2 -0
  4. package/dist/cli.js.map +1 -1
  5. package/dist/commands/index.d.ts +1 -0
  6. package/dist/commands/index.d.ts.map +1 -1
  7. package/dist/commands/index.js +1 -0
  8. package/dist/commands/index.js.map +1 -1
  9. package/dist/commands/scan.d.ts.map +1 -1
  10. package/dist/commands/scan.js +82 -26
  11. package/dist/commands/scan.js.map +1 -1
  12. package/dist/commands/snapshot.d.ts +32 -0
  13. package/dist/commands/snapshot.d.ts.map +1 -0
  14. package/dist/commands/snapshot.js +282 -0
  15. package/dist/commands/snapshot.js.map +1 -0
  16. package/dist/reporters/html.d.ts +3 -2
  17. package/dist/reporters/html.d.ts.map +1 -1
  18. package/dist/reporters/html.js +844 -538
  19. package/dist/reporters/html.js.map +1 -1
  20. package/dist/reporters/terminal.d.ts +38 -2
  21. package/dist/reporters/terminal.d.ts.map +1 -1
  22. package/dist/reporters/terminal.js +292 -131
  23. package/dist/reporters/terminal.js.map +1 -1
  24. package/dist/scanners/auth/analyzer.d.ts +40 -0
  25. package/dist/scanners/auth/analyzer.d.ts.map +1 -0
  26. package/dist/scanners/auth/analyzer.js +673 -0
  27. package/dist/scanners/auth/analyzer.js.map +1 -0
  28. package/dist/scanners/auth/index.d.ts +6 -0
  29. package/dist/scanners/auth/index.d.ts.map +1 -0
  30. package/dist/scanners/auth/index.js +22 -0
  31. package/dist/scanners/auth/index.js.map +1 -0
  32. package/dist/scanners/edge/analyzer.d.ts +35 -0
  33. package/dist/scanners/edge/analyzer.d.ts.map +1 -0
  34. package/dist/scanners/edge/analyzer.js +614 -0
  35. package/dist/scanners/edge/analyzer.js.map +1 -0
  36. package/dist/scanners/edge/index.d.ts +6 -0
  37. package/dist/scanners/edge/index.d.ts.map +1 -0
  38. package/dist/scanners/edge/index.js +22 -0
  39. package/dist/scanners/edge/index.js.map +1 -0
  40. package/dist/scanners/functions/analyzer.d.ts +41 -0
  41. package/dist/scanners/functions/analyzer.d.ts.map +1 -0
  42. package/dist/scanners/functions/analyzer.js +378 -0
  43. package/dist/scanners/functions/analyzer.js.map +1 -0
  44. package/dist/scanners/functions/index.d.ts +6 -0
  45. package/dist/scanners/functions/index.d.ts.map +1 -0
  46. package/dist/scanners/functions/index.js +22 -0
  47. package/dist/scanners/functions/index.js.map +1 -0
  48. package/dist/scanners/git/index.d.ts +6 -0
  49. package/dist/scanners/git/index.d.ts.map +1 -0
  50. package/dist/scanners/git/index.js +22 -0
  51. package/dist/scanners/git/index.js.map +1 -0
  52. package/dist/scanners/git/scanner.d.ts +22 -0
  53. package/dist/scanners/git/scanner.d.ts.map +1 -0
  54. package/dist/scanners/git/scanner.js +531 -0
  55. package/dist/scanners/git/scanner.js.map +1 -0
  56. package/dist/scanners/https/analyzer.d.ts +42 -0
  57. package/dist/scanners/https/analyzer.d.ts.map +1 -0
  58. package/dist/scanners/https/analyzer.js +470 -0
  59. package/dist/scanners/https/analyzer.js.map +1 -0
  60. package/dist/scanners/https/index.d.ts +8 -0
  61. package/dist/scanners/https/index.d.ts.map +1 -0
  62. package/dist/scanners/https/index.js +17 -0
  63. package/dist/scanners/https/index.js.map +1 -0
  64. package/dist/scanners/index.d.ts +6 -0
  65. package/dist/scanners/index.d.ts.map +1 -1
  66. package/dist/scanners/index.js +6 -0
  67. package/dist/scanners/index.js.map +1 -1
  68. package/dist/scanners/rls/fuzzer.d.ts +40 -0
  69. package/dist/scanners/rls/fuzzer.d.ts.map +1 -0
  70. package/dist/scanners/rls/fuzzer.js +360 -0
  71. package/dist/scanners/rls/fuzzer.js.map +1 -0
  72. package/dist/scanners/rls/index.d.ts +1 -0
  73. package/dist/scanners/rls/index.d.ts.map +1 -1
  74. package/dist/scanners/rls/index.js +1 -0
  75. package/dist/scanners/rls/index.js.map +1 -1
  76. package/dist/scanners/secrets/detector.d.ts.map +1 -1
  77. package/dist/scanners/secrets/detector.js +44 -12
  78. package/dist/scanners/secrets/detector.js.map +1 -1
  79. package/dist/scanners/secrets/index.d.ts +1 -0
  80. package/dist/scanners/secrets/index.d.ts.map +1 -1
  81. package/dist/scanners/secrets/index.js +4 -0
  82. package/dist/scanners/secrets/index.js.map +1 -1
  83. package/dist/scanners/secrets/patterns.d.ts +25 -0
  84. package/dist/scanners/secrets/patterns.d.ts.map +1 -1
  85. package/dist/scanners/secrets/patterns.js +138 -27
  86. package/dist/scanners/secrets/patterns.js.map +1 -1
  87. package/dist/scanners/storage/analyzer.d.ts +49 -0
  88. package/dist/scanners/storage/analyzer.d.ts.map +1 -0
  89. package/dist/scanners/storage/analyzer.js +438 -0
  90. package/dist/scanners/storage/analyzer.js.map +1 -0
  91. package/dist/scanners/storage/index.d.ts +6 -0
  92. package/dist/scanners/storage/index.d.ts.map +1 -0
  93. package/dist/scanners/storage/index.js +22 -0
  94. package/dist/scanners/storage/index.js.map +1 -0
  95. package/package.json +1 -1
  96. package/reports/{supasec-audityour-app-2026-01-28-17-09-24.html → supasec-audityour-app-2026-01-28-19-42-22.html} +51 -16
  97. package/reports/supasec-audityour-app-2026-01-28-19-49-18.html +1122 -0
  98. package/COMPLETION_REPORT.md +0 -324
  99. package/FIXES_SUMMARY.md +0 -224
  100. package/IMPLEMENTATION_NOTES.md +0 -305
  101. package/QUICK_REFERENCE.md +0 -185
  102. package/REPORTING.md +0 -217
  103. package/STATUS.md +0 -269
  104. package/reports/supasec---------app-2026-01-28-16-58-47.html +0 -804
  105. package/reports/supasec---------app-2026-01-28-17-06-43.html +0 -722
  106. package/reports/supasec---------app-2026-01-28-17-07-23.html +0 -722
  107. package/reports/supasec---------app-2026-01-28-17-08-00.html +0 -722
  108. package/reports/supasec---------app-2026-01-28-17-08-20.html +0 -722
  109. package/reports/supasec---------app-2026-01-28-17-08-41.html +0 -722
  110. package/reports/supasec-au---your-app-2026-01-28-17-14-57.html +0 -715
  111. package/reports/supasec-au---your-app-2026-01-28-17-19-03.html +0 -715
  112. package/reports/supasec-ex-mple-com-2026-01-28-17-14-52.json +0 -229
  113. package/reports/supasec-ex-mple-com-2026-01-28-17-15-39.html +0 -715
  114. package/reports/supasec-ex-mple-com-2026-01-28-17-17-22.html +0 -715
  115. package/reports/supasec-example-com-2026-01-28-17-15-06.html +0 -715
  116. package/reports/supasec-my--------------name-com-2026-01-28-17-15-02.html +0 -715
  117. package/reports/supasec-st-ging-com-2026-01-28-17-16-17.html +0 -715
@@ -0,0 +1,673 @@
1
+ "use strict";
2
+ /**
3
+ * Auth Configuration Analyzer
4
+ * Scans for authentication and authorization misconfigurations
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.analyzeAuth = analyzeAuth;
8
+ exports.getMockAuthConfig = getMockAuthConfig;
9
+ const finding_js_1 = require("../../models/finding.js");
10
+ /**
11
+ * Analyze auth configuration for security issues
12
+ */
13
+ async function analyzeAuth(options) {
14
+ const findings = [];
15
+ let findingCounter = 1;
16
+ let checksPerformed = 0;
17
+ let score = 100;
18
+ // Check 1: Email verification
19
+ checksPerformed++;
20
+ if (!options.config.emailVerificationRequired) {
21
+ findings.push(createNoEmailVerificationFinding(findingCounter++));
22
+ score -= 15;
23
+ }
24
+ // Check 2: Password policy
25
+ checksPerformed++;
26
+ if (options.config.passwordMinLength < 8) {
27
+ findings.push(createWeakPasswordPolicyFinding(options.config.passwordMinLength, findingCounter++));
28
+ score -= 10;
29
+ }
30
+ // Check 3: Password strength
31
+ checksPerformed++;
32
+ if (options.config.passwordStrength === 'weak') {
33
+ findings.push(createWeakPasswordStrengthFinding(findingCounter++));
34
+ score -= 10;
35
+ }
36
+ // Check 4: MFA
37
+ checksPerformed++;
38
+ if (!options.config.mfaEnabled) {
39
+ findings.push(createNoMFAFinding(findingCounter++));
40
+ score -= 10;
41
+ }
42
+ else if (!options.config.mfaEnforced) {
43
+ findings.push(createMFAOptionalFinding(findingCounter++));
44
+ score -= 5;
45
+ }
46
+ // Check 5: JWT expiry
47
+ checksPerformed++;
48
+ if (options.config.jwtExpirySeconds > 3600) {
49
+ findings.push(createLongJWTExpiryFinding(options.config.jwtExpirySeconds, findingCounter++));
50
+ score -= 5;
51
+ }
52
+ // Check 6: Refresh token rotation
53
+ checksPerformed++;
54
+ if (!options.config.refreshTokenRotation) {
55
+ findings.push(createNoTokenRotationFinding(findingCounter++));
56
+ score -= 10;
57
+ }
58
+ // Check 7: Session timeout
59
+ checksPerformed++;
60
+ if (options.config.sessionTimeoutSeconds > 86400) {
61
+ findings.push(createLongSessionTimeoutFinding(options.config.sessionTimeoutSeconds, findingCounter++));
62
+ score -= 5;
63
+ }
64
+ // Check 8: Anonymous sign-ins
65
+ checksPerformed++;
66
+ if (options.config.allowAnonymousSignIns) {
67
+ findings.push(createAnonymousSignInFinding(findingCounter++));
68
+ score -= 5;
69
+ }
70
+ // Check 9: Secure email change
71
+ checksPerformed++;
72
+ if (!options.config.secureEmailChange) {
73
+ findings.push(createInsecureEmailChangeFinding(findingCounter++));
74
+ score -= 10;
75
+ }
76
+ // Check 10: Password reuse prevention
77
+ checksPerformed++;
78
+ if (options.config.passwordReusePrevention < 3) {
79
+ findings.push(createNoPasswordReusePreventionFinding(findingCounter++));
80
+ score -= 5;
81
+ }
82
+ // Check 11: OAuth providers security
83
+ checksPerformed++;
84
+ const insecureProviders = options.config.providers.filter(p => p.toLowerCase().includes('facebook') ||
85
+ (p.toLowerCase().includes('twitter') && !p.toLowerCase().includes('oauth2')));
86
+ if (insecureProviders.length > 0) {
87
+ findings.push(createInsecureOAuthProviderFinding(insecureProviders, findingCounter++));
88
+ score -= 5;
89
+ }
90
+ return {
91
+ findings,
92
+ checksPerformed,
93
+ misconfigurations: findings.length,
94
+ score: Math.max(0, score)
95
+ };
96
+ }
97
+ /**
98
+ * Create finding for missing email verification
99
+ */
100
+ function createNoEmailVerificationFinding(counter) {
101
+ return {
102
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
103
+ timestamp: new Date().toISOString(),
104
+ severity: 'HIGH',
105
+ category: 'auth',
106
+ subcategory: 'no_email_verification',
107
+ title: 'Email verification is not required',
108
+ description: 'New users can access the application without verifying their email address. This allows account takeover through email typos or fake emails.',
109
+ evidence: {
110
+ email_verification_required: false
111
+ },
112
+ impact: {
113
+ severity_score: 7.5,
114
+ description: 'Account takeover risk - unverified users can access the application',
115
+ affected_resources: ['auth.users', 'auth.config'],
116
+ compliance_violations: ['OWASP-A07-2021', 'NIST-800-63B']
117
+ },
118
+ remediation: {
119
+ summary: 'Enable email verification requirement',
120
+ priority: 'HIGH',
121
+ effort: 'LOW',
122
+ steps: [
123
+ {
124
+ order: 1,
125
+ action: 'Enable email confirmation in Supabase Dashboard',
126
+ code: 'Go to Authentication > Settings > Email > Enable "Confirm email"'
127
+ },
128
+ {
129
+ order: 2,
130
+ action: 'Update client code to handle unverified users',
131
+ code: `// Check if email is verified before allowing access
132
+ const { data: { user } } = await supabase.auth.getUser();
133
+ if (!user?.email_confirmed_at) {
134
+ // Redirect to verification pending page
135
+ }`
136
+ }
137
+ ],
138
+ auto_fixable: true
139
+ },
140
+ references: [
141
+ {
142
+ title: 'Supabase Email Auth',
143
+ url: 'https://supabase.com/docs/guides/auth/auth-email'
144
+ }
145
+ ],
146
+ false_positive_likelihood: 'LOW',
147
+ confidence: 0.95
148
+ };
149
+ }
150
+ /**
151
+ * Create finding for weak password policy
152
+ */
153
+ function createWeakPasswordPolicyFinding(minLength, counter) {
154
+ return {
155
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
156
+ timestamp: new Date().toISOString(),
157
+ severity: 'MEDIUM',
158
+ category: 'auth',
159
+ subcategory: 'weak_password_policy',
160
+ title: `Weak password minimum length (${minLength} characters)`,
161
+ description: `The password policy only requires ${minLength} characters. NIST recommends at least 8 characters for passwords.`,
162
+ evidence: {
163
+ password_min_length: minLength,
164
+ recommended_min_length: 8
165
+ },
166
+ impact: {
167
+ severity_score: 5.0,
168
+ description: 'Short passwords are easier to crack through brute force',
169
+ affected_resources: ['auth.config'],
170
+ compliance_violations: ['NIST-800-63B']
171
+ },
172
+ remediation: {
173
+ summary: 'Increase minimum password length to 8+ characters',
174
+ priority: 'MEDIUM',
175
+ effort: 'LOW',
176
+ steps: [
177
+ {
178
+ order: 1,
179
+ action: 'Update password policy in Supabase Dashboard',
180
+ code: 'Go to Authentication > Policies > Set "Minimum password length" to 8+'
181
+ }
182
+ ],
183
+ auto_fixable: true
184
+ },
185
+ references: [
186
+ {
187
+ title: 'NIST Password Guidelines',
188
+ url: 'https://pages.nist.gov/800-63-3/sp800-63b.html#sec5'
189
+ }
190
+ ],
191
+ false_positive_likelihood: 'LOW',
192
+ confidence: 0.9
193
+ };
194
+ }
195
+ /**
196
+ * Create finding for weak password strength
197
+ */
198
+ function createWeakPasswordStrengthFinding(counter) {
199
+ return {
200
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
201
+ timestamp: new Date().toISOString(),
202
+ severity: 'MEDIUM',
203
+ category: 'auth',
204
+ subcategory: 'weak_password_strength',
205
+ title: 'Password strength policy is set to weak',
206
+ description: 'The password strength policy is set to "weak", allowing common passwords and simple patterns.',
207
+ evidence: {
208
+ password_strength: 'weak'
209
+ },
210
+ impact: {
211
+ severity_score: 5.5,
212
+ description: 'Weak passwords increase risk of account compromise',
213
+ affected_resources: ['auth.config']
214
+ },
215
+ remediation: {
216
+ summary: 'Strengthen password policy',
217
+ priority: 'MEDIUM',
218
+ effort: 'LOW',
219
+ steps: [
220
+ {
221
+ order: 1,
222
+ action: 'Set password strength to "strong"',
223
+ code: 'Go to Authentication > Policies > Set "Password strength" to Strong'
224
+ }
225
+ ],
226
+ auto_fixable: true
227
+ },
228
+ references: [
229
+ {
230
+ title: 'OWASP Password Security',
231
+ url: 'https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html'
232
+ }
233
+ ],
234
+ false_positive_likelihood: 'LOW',
235
+ confidence: 0.9
236
+ };
237
+ }
238
+ /**
239
+ * Create finding for missing MFA
240
+ */
241
+ function createNoMFAFinding(counter) {
242
+ return {
243
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
244
+ timestamp: new Date().toISOString(),
245
+ severity: 'MEDIUM',
246
+ category: 'auth',
247
+ subcategory: 'no_mfa',
248
+ title: 'Multi-factor authentication is not enabled',
249
+ description: 'MFA is not enabled for the project. Users can only authenticate with a single factor (password).',
250
+ evidence: {
251
+ mfa_enabled: false
252
+ },
253
+ impact: {
254
+ severity_score: 6.0,
255
+ description: 'Single factor authentication - password compromise leads to account takeover',
256
+ affected_resources: ['auth.config'],
257
+ compliance_violations: ['NIST-800-63B', 'SOC2-CC6.1']
258
+ },
259
+ remediation: {
260
+ summary: 'Enable multi-factor authentication',
261
+ priority: 'MEDIUM',
262
+ effort: 'MEDIUM',
263
+ steps: [
264
+ {
265
+ order: 1,
266
+ action: 'Enable MFA in Supabase Dashboard',
267
+ code: 'Go to Authentication > Settings > MFA > Enable MFA'
268
+ },
269
+ {
270
+ order: 2,
271
+ action: 'Implement MFA enrollment flow in your app',
272
+ code: `// Enroll MFA
273
+ const { data, error } = await supabase.auth.mfa.enroll({
274
+ factorType: 'totp'
275
+ });
276
+
277
+ // Verify MFA
278
+ const { data, error } = await supabase.auth.mfa.verify({
279
+ factorId,
280
+ code: '123456'
281
+ });`
282
+ }
283
+ ],
284
+ auto_fixable: false
285
+ },
286
+ references: [
287
+ {
288
+ title: 'Supabase MFA Guide',
289
+ url: 'https://supabase.com/docs/guides/auth/auth-mfa'
290
+ }
291
+ ],
292
+ false_positive_likelihood: 'MEDIUM',
293
+ confidence: 0.85
294
+ };
295
+ }
296
+ /**
297
+ * Create finding for optional MFA
298
+ */
299
+ function createMFAOptionalFinding(counter) {
300
+ return {
301
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
302
+ timestamp: new Date().toISOString(),
303
+ severity: 'LOW',
304
+ category: 'auth',
305
+ subcategory: 'mfa_optional',
306
+ title: 'Multi-factor authentication is optional',
307
+ description: 'MFA is enabled but not enforced. Users can choose whether to enable it.',
308
+ evidence: {
309
+ mfa_enabled: true,
310
+ mfa_enforced: false
311
+ },
312
+ impact: {
313
+ severity_score: 3.0,
314
+ description: 'Users may skip MFA, leaving accounts vulnerable',
315
+ affected_resources: ['auth.config']
316
+ },
317
+ remediation: {
318
+ summary: 'Consider enforcing MFA for sensitive operations',
319
+ priority: 'LOW',
320
+ effort: 'MEDIUM',
321
+ steps: [
322
+ {
323
+ order: 1,
324
+ action: 'Require MFA for sensitive operations',
325
+ code: `// Check MFA status before sensitive operations
326
+ const { data: { user } } = await supabase.auth.getUser();
327
+ const aal = user?.aal;
328
+
329
+ if (aal !== 'aal2') {
330
+ // Require MFA verification
331
+ await supabase.auth.mfa.challenge({ factorId });
332
+ }`
333
+ }
334
+ ],
335
+ auto_fixable: false
336
+ },
337
+ references: [
338
+ {
339
+ title: 'Supabase AAL (Authenticator Assurance Level)',
340
+ url: 'https://supabase.com/docs/guides/auth/auth-mfa#enforcing-mfa-for-a-user'
341
+ }
342
+ ],
343
+ false_positive_likelihood: 'HIGH',
344
+ confidence: 0.7
345
+ };
346
+ }
347
+ /**
348
+ * Create finding for long JWT expiry
349
+ */
350
+ function createLongJWTExpiryFinding(expirySeconds, counter) {
351
+ const hours = Math.round(expirySeconds / 3600);
352
+ return {
353
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
354
+ timestamp: new Date().toISOString(),
355
+ severity: 'LOW',
356
+ category: 'auth',
357
+ subcategory: 'long_jwt_expiry',
358
+ title: `JWT tokens expire after ${hours} hours`,
359
+ description: `JWT tokens have a long expiry time (${hours} hours). Shorter expiry times reduce the window of opportunity for token theft.`,
360
+ evidence: {
361
+ jwt_expiry_seconds: expirySeconds,
362
+ jwt_expiry_hours: hours
363
+ },
364
+ impact: {
365
+ severity_score: 3.0,
366
+ description: 'Long-lived tokens increase risk if stolen',
367
+ affected_resources: ['auth.config']
368
+ },
369
+ remediation: {
370
+ summary: 'Reduce JWT expiry time to 1 hour or less',
371
+ priority: 'LOW',
372
+ effort: 'LOW',
373
+ steps: [
374
+ {
375
+ order: 1,
376
+ action: 'Set JWT expiry to 3600 seconds (1 hour)',
377
+ code: 'Go to Authentication > Settings > JWT Settings > JWT expiry limit: 3600'
378
+ }
379
+ ],
380
+ auto_fixable: true
381
+ },
382
+ references: [
383
+ {
384
+ title: 'JWT Security Best Practices',
385
+ url: 'https://tools.ietf.org/html/rfc8725'
386
+ }
387
+ ],
388
+ false_positive_likelihood: 'HIGH',
389
+ confidence: 0.6
390
+ };
391
+ }
392
+ /**
393
+ * Create finding for no token rotation
394
+ */
395
+ function createNoTokenRotationFinding(counter) {
396
+ return {
397
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
398
+ timestamp: new Date().toISOString(),
399
+ severity: 'MEDIUM',
400
+ category: 'auth',
401
+ subcategory: 'no_token_rotation',
402
+ title: 'Refresh token rotation is disabled',
403
+ description: 'Refresh tokens are not rotated on use. If a refresh token is stolen, it can be used indefinitely.',
404
+ evidence: {
405
+ refresh_token_rotation: false
406
+ },
407
+ impact: {
408
+ severity_score: 6.0,
409
+ description: 'Stolen refresh tokens remain valid indefinitely',
410
+ affected_resources: ['auth.config']
411
+ },
412
+ remediation: {
413
+ summary: 'Enable refresh token rotation',
414
+ priority: 'MEDIUM',
415
+ effort: 'LOW',
416
+ steps: [
417
+ {
418
+ order: 1,
419
+ action: 'Enable token rotation in Supabase Dashboard',
420
+ code: 'Go to Authentication > Settings > Security > Enable "Refresh token rotation"'
421
+ }
422
+ ],
423
+ auto_fixable: true
424
+ },
425
+ references: [
426
+ {
427
+ title: 'OWASP Token Security',
428
+ url: 'https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html'
429
+ }
430
+ ],
431
+ false_positive_likelihood: 'LOW',
432
+ confidence: 0.9
433
+ };
434
+ }
435
+ /**
436
+ * Create finding for long session timeout
437
+ */
438
+ function createLongSessionTimeoutFinding(timeoutSeconds, counter) {
439
+ const days = Math.round(timeoutSeconds / 86400);
440
+ return {
441
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
442
+ timestamp: new Date().toISOString(),
443
+ severity: 'LOW',
444
+ category: 'auth',
445
+ subcategory: 'long_session_timeout',
446
+ title: `Sessions expire after ${days} days`,
447
+ description: `User sessions remain active for ${days} days. Shorter timeouts reduce risk on shared devices.`,
448
+ evidence: {
449
+ session_timeout_seconds: timeoutSeconds,
450
+ session_timeout_days: days
451
+ },
452
+ impact: {
453
+ severity_score: 2.5,
454
+ description: 'Long sessions increase risk on shared devices',
455
+ affected_resources: ['auth.config']
456
+ },
457
+ remediation: {
458
+ summary: 'Reduce session timeout to 24 hours or less',
459
+ priority: 'LOW',
460
+ effort: 'LOW',
461
+ steps: [
462
+ {
463
+ order: 1,
464
+ action: 'Set session timeout to 86400 seconds (24 hours)',
465
+ code: 'Go to Authentication > Settings > Sessions > Inactivity timeout: 86400'
466
+ }
467
+ ],
468
+ auto_fixable: true
469
+ },
470
+ references: [
471
+ {
472
+ title: 'Session Management Best Practices',
473
+ url: 'https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html'
474
+ }
475
+ ],
476
+ false_positive_likelihood: 'HIGH',
477
+ confidence: 0.6
478
+ };
479
+ }
480
+ /**
481
+ * Create finding for anonymous sign-ins
482
+ */
483
+ function createAnonymousSignInFinding(counter) {
484
+ return {
485
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
486
+ timestamp: new Date().toISOString(),
487
+ severity: 'LOW',
488
+ category: 'auth',
489
+ subcategory: 'anonymous_signin',
490
+ title: 'Anonymous sign-ins are enabled',
491
+ description: 'Anonymous sign-ins allow users to access the application without providing any credentials.',
492
+ evidence: {
493
+ allow_anonymous_signins: true
494
+ },
495
+ impact: {
496
+ severity_score: 3.0,
497
+ description: 'Anonymous users may abuse resources or access restricted features',
498
+ affected_resources: ['auth.config']
499
+ },
500
+ remediation: {
501
+ summary: 'Review if anonymous sign-ins are necessary',
502
+ priority: 'LOW',
503
+ effort: 'LOW',
504
+ steps: [
505
+ {
506
+ order: 1,
507
+ action: 'Disable anonymous sign-ins if not needed',
508
+ code: 'Go to Authentication > Settings > Enable anonymous sign-ins: OFF'
509
+ }
510
+ ],
511
+ auto_fixable: true
512
+ },
513
+ references: [
514
+ {
515
+ title: 'Supabase Anonymous Sign-Ins',
516
+ url: 'https://supabase.com/docs/guides/auth/auth-anonymous'
517
+ }
518
+ ],
519
+ false_positive_likelihood: 'HIGH',
520
+ confidence: 0.7
521
+ };
522
+ }
523
+ /**
524
+ * Create finding for insecure email change
525
+ */
526
+ function createInsecureEmailChangeFinding(counter) {
527
+ return {
528
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
529
+ timestamp: new Date().toISOString(),
530
+ severity: 'HIGH',
531
+ category: 'auth',
532
+ subcategory: 'insecure_email_change',
533
+ title: 'Secure email change is disabled',
534
+ description: 'Users can change their email address without verification. This enables account takeover.',
535
+ evidence: {
536
+ secure_email_change: false
537
+ },
538
+ impact: {
539
+ severity_score: 8.0,
540
+ description: 'Account takeover through email change - attacker can lock out legitimate user',
541
+ affected_resources: ['auth.config'],
542
+ compliance_violations: ['OWASP-A07-2021']
543
+ },
544
+ remediation: {
545
+ summary: 'Enable secure email change requiring confirmation',
546
+ priority: 'HIGH',
547
+ effort: 'LOW',
548
+ steps: [
549
+ {
550
+ order: 1,
551
+ action: 'Enable secure email change',
552
+ code: 'Go to Authentication > Settings > Email > Enable "Secure email change"'
553
+ }
554
+ ],
555
+ auto_fixable: true
556
+ },
557
+ references: [
558
+ {
559
+ title: 'Supabase Email Security',
560
+ url: 'https://supabase.com/docs/guides/auth/auth-email'
561
+ }
562
+ ],
563
+ false_positive_likelihood: 'LOW',
564
+ confidence: 0.95
565
+ };
566
+ }
567
+ /**
568
+ * Create finding for no password reuse prevention
569
+ */
570
+ function createNoPasswordReusePreventionFinding(counter) {
571
+ return {
572
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
573
+ timestamp: new Date().toISOString(),
574
+ severity: 'LOW',
575
+ category: 'auth',
576
+ subcategory: 'password_reuse',
577
+ title: 'Password reuse prevention is weak',
578
+ description: 'The system does not prevent users from reusing recent passwords.',
579
+ evidence: {
580
+ password_reuse_prevention: 'insufficient'
581
+ },
582
+ impact: {
583
+ severity_score: 3.0,
584
+ description: 'Users can cycle through same passwords, defeating password rotation policies',
585
+ affected_resources: ['auth.config']
586
+ },
587
+ remediation: {
588
+ summary: 'Increase password history retention',
589
+ priority: 'LOW',
590
+ effort: 'LOW',
591
+ steps: [
592
+ {
593
+ order: 1,
594
+ action: 'Set password history to at least 3 previous passwords',
595
+ code: 'Configure password history in your auth policies'
596
+ }
597
+ ],
598
+ auto_fixable: false
599
+ },
600
+ references: [
601
+ {
602
+ title: 'NIST Password Guidelines',
603
+ url: 'https://pages.nist.gov/800-63-3/sp800-63b.html#sec5'
604
+ }
605
+ ],
606
+ false_positive_likelihood: 'HIGH',
607
+ confidence: 0.6
608
+ };
609
+ }
610
+ /**
611
+ * Create finding for insecure OAuth providers
612
+ */
613
+ function createInsecureOAuthProviderFinding(providers, counter) {
614
+ return {
615
+ finding_id: (0, finding_js_1.generateFindingId)('auth', counter),
616
+ timestamp: new Date().toISOString(),
617
+ severity: 'LOW',
618
+ category: 'auth',
619
+ subcategory: 'insecure_oauth',
620
+ title: 'Potentially insecure OAuth providers configured',
621
+ description: `The following OAuth providers may have weaker security: ${providers.join(', ')}. Consider using OAuth 2.0 providers with PKCE.`,
622
+ evidence: {
623
+ providers
624
+ },
625
+ impact: {
626
+ severity_score: 2.5,
627
+ description: 'Some OAuth providers have weaker security guarantees',
628
+ affected_resources: ['auth.config']
629
+ },
630
+ remediation: {
631
+ summary: 'Review OAuth provider security',
632
+ priority: 'LOW',
633
+ effort: 'MEDIUM',
634
+ steps: [
635
+ {
636
+ order: 1,
637
+ action: 'Use OAuth 2.0 with PKCE',
638
+ code: 'Configure providers to use OAuth 2.0 with PKCE flow'
639
+ }
640
+ ],
641
+ auto_fixable: false
642
+ },
643
+ references: [
644
+ {
645
+ title: 'OAuth 2.0 Security Best Practices',
646
+ url: 'https://tools.ietf.org/html/rfc6819'
647
+ }
648
+ ],
649
+ false_positive_likelihood: 'HIGH',
650
+ confidence: 0.6
651
+ };
652
+ }
653
+ /**
654
+ * Mock auth config for testing
655
+ */
656
+ function getMockAuthConfig() {
657
+ return {
658
+ emailVerificationRequired: false,
659
+ emailConfirmationRequired: false,
660
+ passwordMinLength: 6,
661
+ passwordStrength: 'weak',
662
+ mfaEnabled: false,
663
+ mfaEnforced: false,
664
+ providers: ['google', 'github', 'facebook'],
665
+ jwtExpirySeconds: 7200,
666
+ refreshTokenRotation: false,
667
+ sessionTimeoutSeconds: 604800,
668
+ allowAnonymousSignIns: true,
669
+ secureEmailChange: false,
670
+ passwordReusePrevention: 0
671
+ };
672
+ }
673
+ //# sourceMappingURL=analyzer.js.map