guardrail-security 1.0.0

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 (95) hide show
  1. package/dist/attack-surface/analyzer.d.ts +50 -0
  2. package/dist/attack-surface/analyzer.d.ts.map +1 -0
  3. package/dist/attack-surface/analyzer.js +83 -0
  4. package/dist/attack-surface/index.d.ts +5 -0
  5. package/dist/attack-surface/index.d.ts.map +1 -0
  6. package/dist/attack-surface/index.js +20 -0
  7. package/dist/index.d.ts +15 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +33 -0
  10. package/dist/languages/index.d.ts +21 -0
  11. package/dist/languages/index.d.ts.map +1 -0
  12. package/dist/languages/index.js +78 -0
  13. package/dist/languages/java-analyzer.d.ts +72 -0
  14. package/dist/languages/java-analyzer.d.ts.map +1 -0
  15. package/dist/languages/java-analyzer.js +417 -0
  16. package/dist/languages/python-analyzer.d.ts +70 -0
  17. package/dist/languages/python-analyzer.d.ts.map +1 -0
  18. package/dist/languages/python-analyzer.js +425 -0
  19. package/dist/license/compatibility-matrix.d.ts +28 -0
  20. package/dist/license/compatibility-matrix.d.ts.map +1 -0
  21. package/dist/license/compatibility-matrix.js +323 -0
  22. package/dist/license/engine.d.ts +77 -0
  23. package/dist/license/engine.d.ts.map +1 -0
  24. package/dist/license/engine.js +264 -0
  25. package/dist/license/index.d.ts +6 -0
  26. package/dist/license/index.d.ts.map +1 -0
  27. package/dist/license/index.js +21 -0
  28. package/dist/sbom/generator.d.ts +108 -0
  29. package/dist/sbom/generator.d.ts.map +1 -0
  30. package/dist/sbom/generator.js +271 -0
  31. package/dist/sbom/index.d.ts +5 -0
  32. package/dist/sbom/index.d.ts.map +1 -0
  33. package/dist/sbom/index.js +20 -0
  34. package/dist/secrets/guardian.d.ts +113 -0
  35. package/dist/secrets/guardian.d.ts.map +1 -0
  36. package/dist/secrets/guardian.js +334 -0
  37. package/dist/secrets/index.d.ts +10 -0
  38. package/dist/secrets/index.d.ts.map +1 -0
  39. package/dist/secrets/index.js +30 -0
  40. package/dist/secrets/patterns.d.ts +42 -0
  41. package/dist/secrets/patterns.d.ts.map +1 -0
  42. package/dist/secrets/patterns.js +165 -0
  43. package/dist/secrets/pre-commit.d.ts +39 -0
  44. package/dist/secrets/pre-commit.d.ts.map +1 -0
  45. package/dist/secrets/pre-commit.js +127 -0
  46. package/dist/secrets/vault-integration.d.ts +83 -0
  47. package/dist/secrets/vault-integration.d.ts.map +1 -0
  48. package/dist/secrets/vault-integration.js +295 -0
  49. package/dist/secrets/vault-providers.d.ts +110 -0
  50. package/dist/secrets/vault-providers.d.ts.map +1 -0
  51. package/dist/secrets/vault-providers.js +417 -0
  52. package/dist/supply-chain/detector.d.ts +80 -0
  53. package/dist/supply-chain/detector.d.ts.map +1 -0
  54. package/dist/supply-chain/detector.js +168 -0
  55. package/dist/supply-chain/index.d.ts +11 -0
  56. package/dist/supply-chain/index.d.ts.map +1 -0
  57. package/dist/supply-chain/index.js +26 -0
  58. package/dist/supply-chain/malicious-db.d.ts +41 -0
  59. package/dist/supply-chain/malicious-db.d.ts.map +1 -0
  60. package/dist/supply-chain/malicious-db.js +82 -0
  61. package/dist/supply-chain/script-analyzer.d.ts +54 -0
  62. package/dist/supply-chain/script-analyzer.d.ts.map +1 -0
  63. package/dist/supply-chain/script-analyzer.js +160 -0
  64. package/dist/supply-chain/typosquat.d.ts +58 -0
  65. package/dist/supply-chain/typosquat.d.ts.map +1 -0
  66. package/dist/supply-chain/typosquat.js +257 -0
  67. package/dist/supply-chain/vulnerability-db.d.ts +114 -0
  68. package/dist/supply-chain/vulnerability-db.d.ts.map +1 -0
  69. package/dist/supply-chain/vulnerability-db.js +310 -0
  70. package/package.json +34 -0
  71. package/src/__tests__/license/engine.test.ts +250 -0
  72. package/src/__tests__/supply-chain/typosquat.test.ts +191 -0
  73. package/src/attack-surface/analyzer.ts +152 -0
  74. package/src/attack-surface/index.ts +5 -0
  75. package/src/index.ts +21 -0
  76. package/src/languages/index.ts +91 -0
  77. package/src/languages/java-analyzer.ts +490 -0
  78. package/src/languages/python-analyzer.ts +498 -0
  79. package/src/license/compatibility-matrix.ts +366 -0
  80. package/src/license/engine.ts +345 -0
  81. package/src/license/index.ts +6 -0
  82. package/src/sbom/generator.ts +355 -0
  83. package/src/sbom/index.ts +5 -0
  84. package/src/secrets/guardian.ts +448 -0
  85. package/src/secrets/index.ts +10 -0
  86. package/src/secrets/patterns.ts +186 -0
  87. package/src/secrets/pre-commit.ts +158 -0
  88. package/src/secrets/vault-integration.ts +360 -0
  89. package/src/secrets/vault-providers.ts +446 -0
  90. package/src/supply-chain/detector.ts +252 -0
  91. package/src/supply-chain/index.ts +11 -0
  92. package/src/supply-chain/malicious-db.ts +103 -0
  93. package/src/supply-chain/script-analyzer.ts +194 -0
  94. package/src/supply-chain/typosquat.ts +302 -0
  95. package/src/supply-chain/vulnerability-db.ts +386 -0
@@ -0,0 +1,448 @@
1
+ import { prisma } from '@guardrail/database';
2
+ import { calculateEntropy, maskSensitiveValue } from '@guardrail/core';
3
+ import { SECRET_PATTERNS, TEST_PATTERNS, FALSE_POSITIVE_VALUES, SecretPattern } from './patterns';
4
+ import { readFileSync } from 'fs';
5
+ import { glob } from 'glob';
6
+ import { join } from 'path';
7
+
8
+ // Define SecretType locally since it's not exported from database
9
+ export enum SecretType {
10
+ API_KEY = 'api_key',
11
+ PASSWORD = 'password',
12
+ TOKEN = 'token',
13
+ CERTIFICATE = 'certificate',
14
+ PRIVATE_KEY = 'private_key',
15
+ DATABASE_URL = 'database_url',
16
+ JWT_SECRET = 'jwt_secret',
17
+ AWS_ACCESS_KEY = 'aws_access_key',
18
+ OTHER = 'other',
19
+ AWS_SECRET_KEY = 'aws_secret_key',
20
+ GITHUB_TOKEN = 'github_token',
21
+ GOOGLE_API_KEY = 'google_api_key',
22
+ STRIPE_KEY = 'stripe_key',
23
+ JWT_TOKEN = 'jwt_token',
24
+ SLACK_TOKEN = 'slack_token',
25
+ API_KEY_GENERIC = 'api_key_generic',
26
+ PASSWORD_GENERIC = 'password_generic'
27
+ }
28
+
29
+ /**
30
+ * Secret detection result
31
+ */
32
+ export interface SecretDetection {
33
+ id?: string;
34
+ filePath: string;
35
+ secretType: SecretType;
36
+ maskedValue: string;
37
+ location: {
38
+ line: number;
39
+ column: number;
40
+ snippet: string;
41
+ };
42
+ confidence: number;
43
+ entropy: number;
44
+ isTest: boolean;
45
+ isRevoked: boolean;
46
+ recommendation: {
47
+ action: 'remove' | 'move_to_env' | 'use_vault' | 'revoke_and_rotate';
48
+ reason: string;
49
+ remediation: string;
50
+ };
51
+ }
52
+
53
+ /**
54
+ * Scan options
55
+ */
56
+ export interface ScanOptions {
57
+ excludeTests?: boolean;
58
+ minConfidence?: number;
59
+ excludePatterns?: string[];
60
+ }
61
+
62
+ /**
63
+ * Project scan report
64
+ */
65
+ export interface ProjectScanReport {
66
+ projectId: string;
67
+ totalFiles: number;
68
+ scannedFiles: number;
69
+ detections: SecretDetection[];
70
+ summary: {
71
+ totalSecrets: number;
72
+ byType: Record<string, number>;
73
+ byRisk: { high: number; medium: number; low: number };
74
+ };
75
+ }
76
+
77
+ /**
78
+ * Secrets & Credential Guardian
79
+ *
80
+ * Detects exposed secrets and credentials in code
81
+ */
82
+ export class SecretsGuardian {
83
+ /**
84
+ * Scan content for secrets
85
+ */
86
+ async scanContent(
87
+ content: string,
88
+ filePath: string,
89
+ options: ScanOptions = {}
90
+ ): Promise<SecretDetection[]> {
91
+ const detections: SecretDetection[] = [];
92
+ const lines = content.split('\n');
93
+
94
+ for (const pattern of SECRET_PATTERNS) {
95
+ const matches = [...content.matchAll(new RegExp(pattern.pattern, 'g'))];
96
+
97
+ for (const match of matches) {
98
+ if (!match.index) continue;
99
+
100
+ // Extract the secret value (first capturing group)
101
+ const value = match[1] || match[0];
102
+
103
+ // Calculate entropy
104
+ const entropy = this.calculateEntropy(value);
105
+
106
+ // Check minimum entropy requirement
107
+ if (pattern.minEntropy && entropy < pattern.minEntropy) {
108
+ continue;
109
+ }
110
+
111
+ // Find line number and column
112
+ const beforeMatch = content.substring(0, match.index);
113
+ const lineNumber = beforeMatch.split('\n').length;
114
+ const lineStart = beforeMatch.lastIndexOf('\n') + 1;
115
+ const column = match.index - lineStart + 1;
116
+
117
+ // Get context
118
+ const snippet = lines[lineNumber - 1] || '';
119
+
120
+ // Check if it's a test value
121
+ const isTest = this.isTestValue(value, snippet);
122
+
123
+ // Check for false positives
124
+ const isFalsePositive = this.isFalsePositive(value, pattern.type, snippet);
125
+
126
+ if (isFalsePositive) {
127
+ continue;
128
+ }
129
+
130
+ // Calculate confidence
131
+ const confidence = this.calculateConfidence(value, pattern, entropy, isTest);
132
+
133
+ // Skip if below minimum confidence
134
+ if (options.minConfidence && confidence < options.minConfidence) {
135
+ continue;
136
+ }
137
+
138
+ // Skip if excluding tests
139
+ if (options.excludeTests && isTest) {
140
+ continue;
141
+ }
142
+
143
+ // Mask the value
144
+ const maskedValue = this.maskValue(value);
145
+
146
+ // Generate recommendation
147
+ const recommendation = this.generateRecommendation(pattern.type, isTest);
148
+
149
+ // Create detection object
150
+ const detection: SecretDetection = {
151
+ id: undefined, // Will be set when saved to database
152
+ filePath,
153
+ secretType: pattern.type,
154
+ maskedValue,
155
+ location: {
156
+ line: lineNumber,
157
+ column,
158
+ snippet: snippet.trim(),
159
+ },
160
+ confidence,
161
+ entropy,
162
+ isTest,
163
+ isRevoked: false,
164
+ recommendation,
165
+ };
166
+
167
+ detections.push(detection);
168
+ }
169
+ }
170
+
171
+ return detections;
172
+ }
173
+
174
+ /**
175
+ * Scan entire project
176
+ */
177
+ async scanProject(
178
+ projectPath: string,
179
+ projectId: string,
180
+ options: ScanOptions = {}
181
+ ): Promise<ProjectScanReport> {
182
+ const excludePatterns = [
183
+ '**/node_modules/**',
184
+ '**/dist/**',
185
+ '**/build/**',
186
+ '**/.git/**',
187
+ '**/coverage/**',
188
+ '**/*.min.js',
189
+ ...(options.excludePatterns || []),
190
+ ];
191
+
192
+ // Find all files to scan
193
+ const files = await glob('**/*', {
194
+ cwd: projectPath,
195
+ ignore: excludePatterns,
196
+ nodir: true,
197
+ });
198
+
199
+ const allDetections: SecretDetection[] = [];
200
+ let scannedFiles = 0;
201
+
202
+ for (const file of files) {
203
+ try {
204
+ const fullPath = join(projectPath, file);
205
+ const content = readFileSync(fullPath, 'utf-8');
206
+
207
+ const detections = await this.scanContent(content, file, options);
208
+
209
+ // Save to database
210
+ for (const detection of detections) {
211
+ try {
212
+ // @ts-ignore - secretDetection may not exist in schema yet
213
+ await prisma.secretDetection.create({
214
+ data: {
215
+ projectId: 'default',
216
+ filePath: detection.filePath
217
+ } as any
218
+ });
219
+ } catch (error) {
220
+ // Table may not exist - continue
221
+ }
222
+ }
223
+
224
+ allDetections.push(...detections);
225
+ scannedFiles++;
226
+ } catch (error) {
227
+ // Skip files that can't be read
228
+ continue;
229
+ }
230
+ }
231
+
232
+ // Generate summary
233
+ const byType: Record<string, number> = {};
234
+ const byRisk = { high: 0, medium: 0, low: 0 };
235
+
236
+ for (const detection of allDetections) {
237
+ byType[detection.secretType] = (byType[detection.secretType] || 0) + 1;
238
+
239
+ if (detection.confidence >= 0.8) {
240
+ byRisk.high++;
241
+ } else if (detection.confidence >= 0.5) {
242
+ byRisk.medium++;
243
+ } else {
244
+ byRisk.low++;
245
+ }
246
+ }
247
+
248
+ return {
249
+ projectId,
250
+ totalFiles: files.length,
251
+ scannedFiles,
252
+ detections: allDetections,
253
+ summary: {
254
+ totalSecrets: allDetections.length,
255
+ byType,
256
+ byRisk,
257
+ },
258
+ };
259
+ }
260
+
261
+ /**
262
+ * Calculate entropy for randomness detection
263
+ */
264
+ private calculateEntropy(str: string): number {
265
+ return calculateEntropy(str);
266
+ }
267
+
268
+ /**
269
+ * Check if likely test/example value
270
+ */
271
+ private isTestValue(value: string, context: string): boolean {
272
+ const lowerValue = value.toLowerCase();
273
+ const lowerContext = context.toLowerCase();
274
+
275
+ // Check value itself
276
+ for (const pattern of TEST_PATTERNS) {
277
+ if (pattern.test(lowerValue)) {
278
+ return true;
279
+ }
280
+ }
281
+
282
+ // Check context
283
+ if (
284
+ lowerContext.includes('test') ||
285
+ lowerContext.includes('example') ||
286
+ lowerContext.includes('demo') ||
287
+ lowerContext.includes('fixture') ||
288
+ lowerContext.includes('mock')
289
+ ) {
290
+ return true;
291
+ }
292
+
293
+ return false;
294
+ }
295
+
296
+ /**
297
+ * Check for false positives
298
+ */
299
+ private isFalsePositive(value: string, type: SecretType, _context: string): boolean {
300
+ const lowerValue = value.toLowerCase();
301
+
302
+ // Check against known false positives
303
+ if (FALSE_POSITIVE_VALUES.has(lowerValue)) {
304
+ return true;
305
+ }
306
+
307
+ // Check for placeholder patterns
308
+ if (/^(x+|0+|1+|a+)$/i.test(value)) {
309
+ return true;
310
+ }
311
+
312
+ // Check for repeated characters (likely placeholder)
313
+ if (/(.)\1{10,}/.test(value)) {
314
+ return true;
315
+ }
316
+
317
+ // JWT-specific false positive checks
318
+ if (type === SecretType.JWT_TOKEN) {
319
+ // Very simple/short payload might be example
320
+ try {
321
+ const parts = value.split('.');
322
+ if (parts.length === 3 && parts[1]) {
323
+ const payload = Buffer.from(parts[1], 'base64').toString();
324
+ if (payload.length < 20) {
325
+ return true;
326
+ }
327
+ }
328
+ } catch {
329
+ // Invalid JWT, might be false positive
330
+ return true;
331
+ }
332
+ }
333
+
334
+ return false;
335
+ }
336
+
337
+ /**
338
+ * Calculate confidence score
339
+ */
340
+ private calculateConfidence(
341
+ value: string,
342
+ pattern: SecretPattern,
343
+ entropy: number,
344
+ isTest: boolean
345
+ ): number {
346
+ let confidence = 0.7; // Base confidence
347
+
348
+ // Increase confidence for high entropy
349
+ if (entropy > 4.5) {
350
+ confidence += 0.2;
351
+ } else if (entropy > 4.0) {
352
+ confidence += 0.1;
353
+ }
354
+
355
+ // Decrease confidence for test values
356
+ if (isTest) {
357
+ confidence -= 0.3;
358
+ }
359
+
360
+ // Pattern-specific adjustments
361
+ if (pattern.type === SecretType.AWS_ACCESS_KEY && value.startsWith('AKIA')) {
362
+ confidence += 0.1;
363
+ }
364
+
365
+ if (pattern.type === SecretType.GITHUB_TOKEN && /^gh[pos]_/.test(value)) {
366
+ confidence += 0.1;
367
+ }
368
+
369
+ return Math.max(0, Math.min(1, confidence));
370
+ }
371
+
372
+ /**
373
+ * Mask secret for safe logging
374
+ */
375
+ private maskValue(value: string): string {
376
+ return maskSensitiveValue(value);
377
+ }
378
+
379
+ /**
380
+ * Generate recommendation
381
+ */
382
+ private generateRecommendation(
383
+ type: SecretType,
384
+ isTest: boolean
385
+ ): {
386
+ action: 'remove' | 'move_to_env' | 'use_vault' | 'revoke_and_rotate';
387
+ reason: string;
388
+ remediation: string;
389
+ } {
390
+ if (isTest) {
391
+ return {
392
+ action: 'remove',
393
+ reason: 'Test credential detected in code',
394
+ remediation: 'Remove test credentials and use mocking instead',
395
+ };
396
+ }
397
+
398
+ // High-risk secrets require rotation
399
+ const highRiskTypes: SecretType[] = [
400
+ 'AWS_SECRET_KEY' as SecretType,
401
+ 'GITHUB_TOKEN' as SecretType,
402
+ 'STRIPE_KEY' as SecretType,
403
+ 'PRIVATE_KEY' as SecretType,
404
+ ];
405
+
406
+ if (highRiskTypes.includes(type)) {
407
+ return {
408
+ action: 'revoke_and_rotate',
409
+ reason: 'High-risk credential exposed in code',
410
+ remediation: 'Immediately revoke this credential and rotate to a new one. Store in secure vault or environment variables.',
411
+ };
412
+ }
413
+
414
+ // Medium-risk can use env vars
415
+ return {
416
+ action: 'move_to_env',
417
+ reason: 'Credential should not be hardcoded',
418
+ remediation: 'Move to environment variables or secure vault (e.g., AWS Secrets Manager, HashiCorp Vault)',
419
+ };
420
+ }
421
+
422
+ /**
423
+ * Get project secrets report
424
+ */
425
+ async getProjectReport(projectId: string): Promise<SecretDetection[]> {
426
+ // @ts-ignore - secretDetection may not exist in schema yet
427
+ const detections = await prisma.secretDetection.findMany({
428
+ where: { projectId },
429
+ orderBy: { createdAt: 'desc' },
430
+ });
431
+
432
+ return detections.map((s: any) => ({
433
+ id: s.id,
434
+ filePath: s.filePath,
435
+ secretType: s.secretType as SecretType,
436
+ maskedValue: s.maskedValue,
437
+ location: s.location as any,
438
+ confidence: s.confidence,
439
+ entropy: s.entropy,
440
+ isTest: s.isTest,
441
+ isRevoked: s.isRevoked,
442
+ recommendation: s.recommendation as any,
443
+ }));
444
+ }
445
+ }
446
+
447
+ // Export singleton
448
+ export const secretsGuardian = new SecretsGuardian();
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Secrets & Credential Guardian
3
+ *
4
+ * Detects and prevents exposure of secrets and credentials
5
+ */
6
+
7
+ export * from './patterns';
8
+ export { secretsGuardian, SecretsGuardian } from './guardian';
9
+ export { preCommitHook } from './pre-commit';
10
+ export { vaultIntegration } from './vault-integration';
@@ -0,0 +1,186 @@
1
+ // Define SecretType locally since it's not exported from database
2
+ export enum SecretType {
3
+ API_KEY = 'api_key',
4
+ PASSWORD = 'password',
5
+ TOKEN = 'token',
6
+ CERTIFICATE = 'certificate',
7
+ PRIVATE_KEY = 'private_key',
8
+ DATABASE_URL = 'database_url',
9
+ JWT_SECRET = 'jwt_secret',
10
+ AWS_ACCESS_KEY = 'aws_access_key',
11
+ OTHER = 'other',
12
+ AWS_SECRET_KEY = 'aws_secret_key',
13
+ GITHUB_TOKEN = 'github_token',
14
+ GOOGLE_API_KEY = 'google_api_key',
15
+ STRIPE_KEY = 'stripe_key',
16
+ JWT_TOKEN = 'jwt_token',
17
+ SLACK_TOKEN = 'slack_token',
18
+ API_KEY_GENERIC = 'api_key_generic',
19
+ }
20
+
21
+ /**
22
+ * Secret detection pattern
23
+ */
24
+ export interface SecretPattern {
25
+ type: SecretType;
26
+ name: string;
27
+ pattern: RegExp;
28
+ minEntropy?: number;
29
+ description: string;
30
+ examples: string[];
31
+ }
32
+
33
+ /**
34
+ * Comprehensive secret detection patterns
35
+ */
36
+ export const SECRET_PATTERNS: SecretPattern[] = [
37
+ // AWS Access Keys
38
+ {
39
+ type: 'AWS_ACCESS_KEY' as SecretType,
40
+ name: 'AWS Access Key ID',
41
+ pattern: /(AKIA[0-9A-Z]{16})/,
42
+ minEntropy: 3.5,
43
+ description: 'AWS Access Key ID (starts with AKIA)',
44
+ examples: ['AKIAIOSFODNN7EXAMPLE'],
45
+ },
46
+
47
+ // AWS Secret Keys
48
+ {
49
+ type: 'AWS_SECRET_KEY' as SecretType,
50
+ name: 'AWS Secret Access Key',
51
+ pattern: /aws[_\s]*secret[_\s]*access[_\s]*key[_\s]*[=:]\s*['"]?([A-Za-z0-9/+=]{40})['"]?/i,
52
+ minEntropy: 4.5,
53
+ description: 'AWS Secret Access Key (40 characters)',
54
+ examples: ['aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY'],
55
+ },
56
+
57
+ // GitHub Personal Access Tokens
58
+ {
59
+ type: 'GITHUB_TOKEN' as SecretType,
60
+ name: 'GitHub Personal Access Token',
61
+ pattern: /(ghp_[a-zA-Z0-9]{36}|gho_[a-zA-Z0-9]{36}|ghu_[a-zA-Z0-9]{36}|ghs_[a-zA-Z0-9]{36}|ghr_[a-zA-Z0-9]{36})/,
62
+ description: 'GitHub Personal Access Token (ghp_, gho_, ghu_, ghs_, ghr_)',
63
+ examples: ['ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
64
+ },
65
+
66
+ // Google API Keys
67
+ {
68
+ type: 'GOOGLE_API_KEY' as SecretType,
69
+ name: 'Google API Key',
70
+ pattern: /(AIza[0-9A-Za-z\-_]{35})/,
71
+ description: 'Google API Key (starts with AIza)',
72
+ examples: ['AIzaSyDaGmWKa4JsXZ-HjGw7ISLn_3namBGewQe'],
73
+ },
74
+
75
+ // Stripe API Keys
76
+ {
77
+ type: 'STRIPE_KEY' as SecretType,
78
+ name: 'Stripe API Key',
79
+ pattern: /(sk_live_[0-9a-zA-Z]{24,}|pk_live_[0-9a-zA-Z]{24,}|rk_live_[0-9a-zA-Z]{24,})/,
80
+ description: 'Stripe Live API Key',
81
+ examples: ['sk_live_1234567890abcdefghijklmn'],
82
+ },
83
+
84
+ // JWT Tokens
85
+ {
86
+ type: 'JWT_TOKEN' as SecretType,
87
+ name: 'JWT Token',
88
+ pattern: /(eyJ[a-zA-Z0-9_-]*\.eyJ[a-zA-Z0-9_-]*\.[a-zA-Z0-9_-]+)/,
89
+ minEntropy: 4.0,
90
+ description: 'JSON Web Token (JWT)',
91
+ examples: ['eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U'],
92
+ },
93
+
94
+ // Private Keys
95
+ {
96
+ type: 'PRIVATE_KEY' as SecretType,
97
+ name: 'Private Key',
98
+ pattern: /(-----BEGIN (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----[\s\S]*?-----END (RSA |EC |OPENSSH |DSA )?PRIVATE KEY-----)/,
99
+ description: 'Private Key (RSA, EC, OpenSSH, DSA)',
100
+ examples: ['-----BEGIN PRIVATE KEY-----\\nMIIEvQIBADANBgk...\\n-----END PRIVATE KEY-----'],
101
+ },
102
+
103
+ // Database URLs with credentials
104
+ {
105
+ type: 'DATABASE_URL' as SecretType,
106
+ name: 'Database URL with Password',
107
+ pattern: /(postgres|mysql|mongodb|redis):\/\/[a-zA-Z0-9_-]+:([a-zA-Z0-9!@#$%^&*()_+\-=\[\]{};':"\\|,.<>\/?]+)@[a-zA-Z0-9.-]+:[0-9]+/,
108
+ minEntropy: 3.0,
109
+ description: 'Database connection string with embedded password',
110
+ examples: ['postgresql://user:password123@localhost:5432/dbname'],
111
+ },
112
+
113
+ // Slack Tokens
114
+ {
115
+ type: 'SLACK_TOKEN' as SecretType,
116
+ name: 'Slack Token',
117
+ pattern: /(xox[pboa]-[0-9]{10,13}-[0-9]{10,13}-[0-9]{10,13}-[a-z0-9]{32})/,
118
+ description: 'Slack Bot/User/App Token',
119
+ examples: ['xoxb-0000000000-0000000000-0000000000-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'],
120
+ },
121
+
122
+ // Generic API Keys (high entropy)
123
+ {
124
+ type: 'API_KEY_GENERIC' as SecretType,
125
+ name: 'Generic API Key',
126
+ pattern: /(?:api[_\s-]?key|apikey|access[_\s-]?token|auth[_\s-]?token|secret[_\s-]?key)[_\s]*[=:]\s*['"]?([a-zA-Z0-9_\-]{32,})['"]?/i,
127
+ minEntropy: 4.0,
128
+ description: 'Generic API key or access token (high entropy)',
129
+ examples: ['api_key = abcdef1234567890abcdef1234567890'],
130
+ },
131
+
132
+ // Generic Passwords
133
+ {
134
+ type: 'PASSWORD_GENERIC' as SecretType,
135
+ name: 'Generic Password',
136
+ pattern: /(?:password|passwd|pwd)[_\s]*[=:]\s*['"]([^'"]{8,})['"]|(?:password|passwd|pwd)[_\s]*[=:]\s*([^\s]{8,})/i,
137
+ minEntropy: 3.0,
138
+ description: 'Generic password in configuration',
139
+ examples: ['password = "MySecretP@ssw0rd"'],
140
+ },
141
+ ];
142
+
143
+ /**
144
+ * Test/example value patterns (to exclude false positives)
145
+ */
146
+ export const TEST_PATTERNS = [
147
+ /test/i,
148
+ /example/i,
149
+ /sample/i,
150
+ /demo/i,
151
+ /fake/i,
152
+ /dummy/i,
153
+ /placeholder/i,
154
+ /\*{3,}/,
155
+ /x{3,}/i,
156
+ /0{5,}/,
157
+ /1{5,}/,
158
+ /abc{3,}/i,
159
+ /qwerty/i,
160
+ /password123/i,
161
+ /changeme/i,
162
+ /your[_-]?key/i,
163
+ /your[_-]?secret/i,
164
+ ];
165
+
166
+ /**
167
+ * Common false positive values
168
+ */
169
+ export const FALSE_POSITIVE_VALUES = new Set([
170
+ 'example',
171
+ 'test',
172
+ 'sample',
173
+ 'demo',
174
+ 'placeholder',
175
+ 'your_key_here',
176
+ 'your_secret_here',
177
+ 'xxx',
178
+ 'yyy',
179
+ 'zzz',
180
+ '***',
181
+ '000000000000',
182
+ '111111111111',
183
+ 'abcdefghijklmnopqrstuvwxyz',
184
+ 'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
185
+ '1234567890',
186
+ ]);