supasec 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.
- package/.env +1 -0
- package/LICENSE +21 -0
- package/README.md +276 -0
- package/dist/cli.d.ts +7 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +30 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/index.d.ts +6 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +22 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/scan.d.ts +23 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +235 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/models/finding.d.ts +88 -0
- package/dist/models/finding.d.ts.map +1 -0
- package/dist/models/finding.js +80 -0
- package/dist/models/finding.js.map +1 -0
- package/dist/models/index.d.ts +7 -0
- package/dist/models/index.d.ts.map +1 -0
- package/dist/models/index.js +23 -0
- package/dist/models/index.js.map +1 -0
- package/dist/models/scan-result.d.ts +103 -0
- package/dist/models/scan-result.d.ts.map +1 -0
- package/dist/models/scan-result.js +168 -0
- package/dist/models/scan-result.js.map +1 -0
- package/dist/reporters/index.d.ts +6 -0
- package/dist/reporters/index.d.ts.map +1 -0
- package/dist/reporters/index.js +22 -0
- package/dist/reporters/index.js.map +1 -0
- package/dist/reporters/terminal.d.ts +20 -0
- package/dist/reporters/terminal.d.ts.map +1 -0
- package/dist/reporters/terminal.js +346 -0
- package/dist/reporters/terminal.js.map +1 -0
- package/dist/scanners/index.d.ts +7 -0
- package/dist/scanners/index.d.ts.map +1 -0
- package/dist/scanners/index.js +23 -0
- package/dist/scanners/index.js.map +1 -0
- package/dist/scanners/rls/analyzer.d.ts +44 -0
- package/dist/scanners/rls/analyzer.d.ts.map +1 -0
- package/dist/scanners/rls/analyzer.js +519 -0
- package/dist/scanners/rls/analyzer.js.map +1 -0
- package/dist/scanners/rls/index.d.ts +6 -0
- package/dist/scanners/rls/index.d.ts.map +1 -0
- package/dist/scanners/rls/index.js +22 -0
- package/dist/scanners/rls/index.js.map +1 -0
- package/dist/scanners/secrets/detector.d.ts +32 -0
- package/dist/scanners/secrets/detector.d.ts.map +1 -0
- package/dist/scanners/secrets/detector.js +251 -0
- package/dist/scanners/secrets/detector.js.map +1 -0
- package/dist/scanners/secrets/index.d.ts +7 -0
- package/dist/scanners/secrets/index.d.ts.map +1 -0
- package/dist/scanners/secrets/index.js +23 -0
- package/dist/scanners/secrets/index.js.map +1 -0
- package/dist/scanners/secrets/patterns.d.ts +57 -0
- package/dist/scanners/secrets/patterns.d.ts.map +1 -0
- package/dist/scanners/secrets/patterns.js +285 -0
- package/dist/scanners/secrets/patterns.js.map +1 -0
- package/npm-publishing-guide.md +38 -0
- package/package.json +69 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Secrets Detector
|
|
4
|
+
* Main scanner module for detecting exposed secrets in frontend bundles
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.scanForSecrets = scanForSecrets;
|
|
8
|
+
exports.scanJavaScriptBundle = scanJavaScriptBundle;
|
|
9
|
+
exports.scanHTML = scanHTML;
|
|
10
|
+
exports.scanSourceMap = scanSourceMap;
|
|
11
|
+
const finding_js_1 = require("../../models/finding.js");
|
|
12
|
+
const patterns_js_1 = require("./patterns.js");
|
|
13
|
+
/**
|
|
14
|
+
* Scan content for exposed secrets
|
|
15
|
+
*/
|
|
16
|
+
async function scanForSecrets(options) {
|
|
17
|
+
const startTime = Date.now();
|
|
18
|
+
const findings = [];
|
|
19
|
+
let findingCounter = 1;
|
|
20
|
+
// Detect all secrets
|
|
21
|
+
const detected = (0, patterns_js_1.detectSecrets)(options.content, patterns_js_1.allPatterns);
|
|
22
|
+
for (const secret of detected) {
|
|
23
|
+
const finding = createFindingFromSecret(secret, options, findingCounter++);
|
|
24
|
+
if (finding) {
|
|
25
|
+
findings.push(finding);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
const scanDurationMs = Date.now() - startTime;
|
|
29
|
+
return {
|
|
30
|
+
findings,
|
|
31
|
+
scannedBytes: options.content.length,
|
|
32
|
+
scanDurationMs
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Create a Finding from a detected secret
|
|
37
|
+
*/
|
|
38
|
+
function createFindingFromSecret(secret, options, counter) {
|
|
39
|
+
const severity = mapSeverity(secret.pattern.severity);
|
|
40
|
+
const category = 'secrets';
|
|
41
|
+
// Skip INFO level findings for secrets
|
|
42
|
+
if (severity === 'INFO') {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
const findingId = (0, finding_js_1.generateFindingId)(category, counter);
|
|
46
|
+
return {
|
|
47
|
+
finding_id: findingId,
|
|
48
|
+
timestamp: new Date().toISOString(),
|
|
49
|
+
severity,
|
|
50
|
+
category,
|
|
51
|
+
subcategory: secret.pattern.category,
|
|
52
|
+
title: `${secret.pattern.name} Exposed`,
|
|
53
|
+
description: `Found ${secret.pattern.name.toLowerCase()} in ${options.sourceType} content. ${secret.pattern.description}`,
|
|
54
|
+
location: {
|
|
55
|
+
file: options.sourceUrl,
|
|
56
|
+
line: secret.line,
|
|
57
|
+
column: secret.column
|
|
58
|
+
},
|
|
59
|
+
evidence: {
|
|
60
|
+
code_snippet: secret.match,
|
|
61
|
+
matched_pattern: secret.pattern.name,
|
|
62
|
+
sample_data: {
|
|
63
|
+
masked: secret.masked
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
impact: {
|
|
67
|
+
severity_score: severity === 'CRITICAL' ? 10.0 : severity === 'HIGH' ? 8.0 : 5.0,
|
|
68
|
+
description: getImpactDescription(secret.pattern.category),
|
|
69
|
+
affected_resources: ['application', 'database', 'api'],
|
|
70
|
+
compliance_violations: getComplianceViolations(secret.pattern.category)
|
|
71
|
+
},
|
|
72
|
+
remediation: {
|
|
73
|
+
summary: `Remove ${secret.pattern.name.toLowerCase()} from client-side code`,
|
|
74
|
+
priority: severity === 'CRITICAL' ? 'IMMEDIATE' : 'HIGH',
|
|
75
|
+
effort: 'LOW',
|
|
76
|
+
steps: getRemediationSteps(secret.pattern.category),
|
|
77
|
+
auto_fixable: false
|
|
78
|
+
},
|
|
79
|
+
references: getReferences(secret.pattern.category),
|
|
80
|
+
false_positive_likelihood: 'LOW',
|
|
81
|
+
confidence: 0.95
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Map pattern severity to Finding severity
|
|
86
|
+
*/
|
|
87
|
+
function mapSeverity(patternSeverity) {
|
|
88
|
+
switch (patternSeverity) {
|
|
89
|
+
case 'CRITICAL':
|
|
90
|
+
return 'CRITICAL';
|
|
91
|
+
case 'HIGH':
|
|
92
|
+
return 'HIGH';
|
|
93
|
+
case 'MEDIUM':
|
|
94
|
+
return 'MEDIUM';
|
|
95
|
+
default:
|
|
96
|
+
return 'INFO';
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Get impact description based on category
|
|
101
|
+
*/
|
|
102
|
+
function getImpactDescription(category) {
|
|
103
|
+
const descriptions = {
|
|
104
|
+
supabase: 'Complete database access - attacker can read, write, and delete all data',
|
|
105
|
+
payment: 'Financial data exposure - potential fraud and unauthorized transactions',
|
|
106
|
+
ai: 'API abuse and quota exhaustion - potential for unauthorized AI usage',
|
|
107
|
+
vcs: 'Source code access - potential for supply chain attacks',
|
|
108
|
+
cloud: 'Cloud infrastructure access - potential for data breaches and resource abuse',
|
|
109
|
+
email: 'Email service abuse - potential for spam and phishing',
|
|
110
|
+
sms: 'SMS service abuse - potential for fraud and high costs',
|
|
111
|
+
messaging: 'Messaging platform abuse - potential for data leaks',
|
|
112
|
+
generic: 'Unauthorized API access - potential for data breaches',
|
|
113
|
+
crypto: 'Cryptographic key exposure - complete security compromise',
|
|
114
|
+
auth: 'Authentication token exposure - unauthorized access to user accounts',
|
|
115
|
+
config: 'Configuration secret exposure - potential for system compromise'
|
|
116
|
+
};
|
|
117
|
+
return descriptions[category] || 'Potential unauthorized access to sensitive resources';
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get compliance violations based on category
|
|
121
|
+
*/
|
|
122
|
+
function getComplianceViolations(category) {
|
|
123
|
+
const violations = {
|
|
124
|
+
supabase: ['SOC2-CC6.1', 'GDPR-Article-32'],
|
|
125
|
+
payment: ['PCI-DSS-3.2', 'SOC2-CC6.1'],
|
|
126
|
+
ai: ['SOC2-CC6.1'],
|
|
127
|
+
vcs: ['SOC2-CC6.1'],
|
|
128
|
+
cloud: ['SOC2-CC6.1', 'GDPR-Article-32'],
|
|
129
|
+
email: ['SOC2-CC6.1'],
|
|
130
|
+
sms: ['SOC2-CC6.1'],
|
|
131
|
+
messaging: ['SOC2-CC6.1'],
|
|
132
|
+
generic: ['SOC2-CC6.1'],
|
|
133
|
+
crypto: ['SOC2-CC6.1', 'GDPR-Article-32', 'FIPS-140-2'],
|
|
134
|
+
auth: ['SOC2-CC6.1', 'OWASP-A02-2021'],
|
|
135
|
+
config: ['SOC2-CC6.1']
|
|
136
|
+
};
|
|
137
|
+
return violations[category] || ['SOC2-CC6.1'];
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get remediation steps based on category
|
|
141
|
+
*/
|
|
142
|
+
function getRemediationSteps(category) {
|
|
143
|
+
const commonSteps = [
|
|
144
|
+
{
|
|
145
|
+
order: 1,
|
|
146
|
+
action: 'Remove the exposed secret from client-side code immediately',
|
|
147
|
+
code: '// Remove hardcoded key\nconst supabaseKey = process.env.SUPABASE_KEY;'
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
order: 2,
|
|
151
|
+
action: 'Move the secret to environment variables on the server',
|
|
152
|
+
command: 'export API_KEY=your_key_here'
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
order: 3,
|
|
156
|
+
action: 'Regenerate the exposed secret to invalidate the compromised key',
|
|
157
|
+
command: 'Regenerate in service dashboard'
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
order: 4,
|
|
161
|
+
action: 'Use only the anon/public key in frontend code',
|
|
162
|
+
code: 'const supabase = createClient(url, process.env.SUPABASE_ANON_KEY)'
|
|
163
|
+
}
|
|
164
|
+
];
|
|
165
|
+
if (category === 'supabase') {
|
|
166
|
+
return [
|
|
167
|
+
{
|
|
168
|
+
order: 1,
|
|
169
|
+
action: 'Regenerate the service_role key in Supabase dashboard',
|
|
170
|
+
command: 'Dashboard > Settings > API > Regenerate service_role key'
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
order: 2,
|
|
174
|
+
action: 'Move service_role key to backend environment variables only',
|
|
175
|
+
code: '// Server-side only\nconst supabase = createClient(url, process.env.SUPABASE_SERVICE_ROLE_KEY)'
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
order: 3,
|
|
179
|
+
action: 'Use anon key for client-side operations',
|
|
180
|
+
code: '// Client-side\nconst supabase = createClient(url, process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY)'
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
order: 4,
|
|
184
|
+
action: 'Review database access logs for unauthorized access'
|
|
185
|
+
}
|
|
186
|
+
];
|
|
187
|
+
}
|
|
188
|
+
return commonSteps;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Get reference links based on category
|
|
192
|
+
*/
|
|
193
|
+
function getReferences(category) {
|
|
194
|
+
const references = {
|
|
195
|
+
supabase: [
|
|
196
|
+
{ title: 'Supabase API Keys Documentation', url: 'https://supabase.com/docs/guides/api#api-keys' },
|
|
197
|
+
{ title: 'CWE-798: Use of Hard-coded Credentials', url: 'https://cwe.mitre.org/data/definitions/798.html' }
|
|
198
|
+
],
|
|
199
|
+
payment: [
|
|
200
|
+
{ title: 'Stripe Security Best Practices', url: 'https://stripe.com/docs/security' },
|
|
201
|
+
{ title: 'PCI DSS Requirements', url: 'https://www.pcisecuritystandards.org/' }
|
|
202
|
+
],
|
|
203
|
+
ai: [
|
|
204
|
+
{ title: 'OpenAI API Security', url: 'https://platform.openai.com/docs/guides/safety-best-practices' }
|
|
205
|
+
],
|
|
206
|
+
cloud: [
|
|
207
|
+
{ title: 'AWS Security Best Practices', url: 'https://docs.aws.amazon.com/security/' }
|
|
208
|
+
],
|
|
209
|
+
crypto: [
|
|
210
|
+
{ title: 'OWASP Cryptographic Storage Cheat Sheet', url: 'https://cheatsheetseries.owasp.org/cheatsheets/Cryptographic_Storage_Cheat_Sheet.html' }
|
|
211
|
+
],
|
|
212
|
+
auth: [
|
|
213
|
+
{ title: 'OWASP Authentication Cheat Sheet', url: 'https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html' }
|
|
214
|
+
]
|
|
215
|
+
};
|
|
216
|
+
return references[category] || [
|
|
217
|
+
{ title: 'OWASP Secrets Management Cheat Sheet', url: 'https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html' },
|
|
218
|
+
{ title: 'CWE-798: Use of Hard-coded Credentials', url: 'https://cwe.mitre.org/data/definitions/798.html' }
|
|
219
|
+
];
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Scan JavaScript bundle for secrets
|
|
223
|
+
*/
|
|
224
|
+
async function scanJavaScriptBundle(jsContent, url) {
|
|
225
|
+
return scanForSecrets({
|
|
226
|
+
content: jsContent,
|
|
227
|
+
sourceUrl: url,
|
|
228
|
+
sourceType: 'javascript'
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Scan HTML content for secrets
|
|
233
|
+
*/
|
|
234
|
+
async function scanHTML(htmlContent, url) {
|
|
235
|
+
return scanForSecrets({
|
|
236
|
+
content: htmlContent,
|
|
237
|
+
sourceUrl: url,
|
|
238
|
+
sourceType: 'html'
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Scan source map for secrets
|
|
243
|
+
*/
|
|
244
|
+
async function scanSourceMap(sourceMapContent, url) {
|
|
245
|
+
return scanForSecrets({
|
|
246
|
+
content: sourceMapContent,
|
|
247
|
+
sourceUrl: url,
|
|
248
|
+
sourceType: 'sourcemap'
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
//# sourceMappingURL=detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detector.js","sourceRoot":"","sources":["../../../src/scanners/secrets/detector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/scanners/secrets/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Secrets Scanner Module
|
|
4
|
+
* Export all secrets detection functionality
|
|
5
|
+
*/
|
|
6
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
7
|
+
if (k2 === undefined) k2 = k;
|
|
8
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
9
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
10
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
11
|
+
}
|
|
12
|
+
Object.defineProperty(o, k2, desc);
|
|
13
|
+
}) : (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
o[k2] = m[k];
|
|
16
|
+
}));
|
|
17
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
18
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
|
+
};
|
|
20
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
+
__exportStar(require("./patterns.js"), exports);
|
|
22
|
+
__exportStar(require("./detector.js"), exports);
|
|
23
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/scanners/secrets/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;AAEH,gDAA8B;AAC9B,gDAA8B"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Secret Detection Patterns
|
|
3
|
+
* Regex patterns and detection logic for various secrets
|
|
4
|
+
*/
|
|
5
|
+
export interface SecretPattern {
|
|
6
|
+
name: string;
|
|
7
|
+
pattern: RegExp;
|
|
8
|
+
severity: 'CRITICAL' | 'HIGH' | 'MEDIUM' | 'INFO';
|
|
9
|
+
category: string;
|
|
10
|
+
description: string;
|
|
11
|
+
validator?: (match: string) => boolean;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Supabase-specific patterns
|
|
15
|
+
*/
|
|
16
|
+
export declare const supabasePatterns: SecretPattern[];
|
|
17
|
+
/**
|
|
18
|
+
* Third-party API key patterns
|
|
19
|
+
*/
|
|
20
|
+
export declare const apiKeyPatterns: SecretPattern[];
|
|
21
|
+
/**
|
|
22
|
+
* Generic secret patterns
|
|
23
|
+
*/
|
|
24
|
+
export declare const genericPatterns: SecretPattern[];
|
|
25
|
+
/**
|
|
26
|
+
* Environment variable patterns (for .env files)
|
|
27
|
+
*/
|
|
28
|
+
export declare const envPatterns: SecretPattern[];
|
|
29
|
+
/**
|
|
30
|
+
* All patterns combined
|
|
31
|
+
*/
|
|
32
|
+
export declare const allPatterns: SecretPattern[];
|
|
33
|
+
/**
|
|
34
|
+
* Calculate Shannon entropy of a string
|
|
35
|
+
* Used to detect high-entropy strings that might be secrets
|
|
36
|
+
*/
|
|
37
|
+
export declare function calculateEntropy(str: string): number;
|
|
38
|
+
/**
|
|
39
|
+
* Check if a string has high entropy (likely a secret)
|
|
40
|
+
*/
|
|
41
|
+
export declare function hasHighEntropy(str: string, threshold?: number): boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Mask a secret for display
|
|
44
|
+
*/
|
|
45
|
+
export declare function maskSecret(secret: string, visibleChars?: number): string;
|
|
46
|
+
/**
|
|
47
|
+
* Detect secrets in text content
|
|
48
|
+
*/
|
|
49
|
+
export interface DetectedSecret {
|
|
50
|
+
pattern: SecretPattern;
|
|
51
|
+
match: string;
|
|
52
|
+
line: number;
|
|
53
|
+
column: number;
|
|
54
|
+
masked: string;
|
|
55
|
+
}
|
|
56
|
+
export declare function detectSecrets(content: string, patterns?: SecretPattern[]): DetectedSecret[];
|
|
57
|
+
//# sourceMappingURL=patterns.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../../src/scanners/secrets/patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;IAClD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC;CACxC;AAED;;GAEG;AACH,eAAO,MAAM,gBAAgB,EAAE,aAAa,EAwD3C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,EAAE,aAAa,EAuEzC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,aAAa,EAoC1C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,aAAa,EAQtC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,aAAa,EAKtC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAgBpD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,GAAE,MAAY,GAAG,OAAO,CAE5E;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,GAAE,MAAU,GAAG,MAAM,CAU3E;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,aAAa,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,aAAa,EAAgB,GAAG,cAAc,EAAE,CA4CxG"}
|
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Secret Detection Patterns
|
|
4
|
+
* Regex patterns and detection logic for various secrets
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.allPatterns = exports.envPatterns = exports.genericPatterns = exports.apiKeyPatterns = exports.supabasePatterns = void 0;
|
|
8
|
+
exports.calculateEntropy = calculateEntropy;
|
|
9
|
+
exports.hasHighEntropy = hasHighEntropy;
|
|
10
|
+
exports.maskSecret = maskSecret;
|
|
11
|
+
exports.detectSecrets = detectSecrets;
|
|
12
|
+
/**
|
|
13
|
+
* Supabase-specific patterns
|
|
14
|
+
*/
|
|
15
|
+
exports.supabasePatterns = [
|
|
16
|
+
{
|
|
17
|
+
name: 'Supabase Service Role Key',
|
|
18
|
+
pattern: /eyJ[A-Za-z0-9-_]*\.eyJ[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*/g,
|
|
19
|
+
severity: 'CRITICAL',
|
|
20
|
+
category: 'supabase',
|
|
21
|
+
description: 'Potential Supabase JWT token - needs role verification',
|
|
22
|
+
validator: (match) => {
|
|
23
|
+
// Check if it's a valid JWT format
|
|
24
|
+
const parts = match.split('.');
|
|
25
|
+
if (parts.length !== 3)
|
|
26
|
+
return false;
|
|
27
|
+
try {
|
|
28
|
+
// Decode payload
|
|
29
|
+
const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
|
|
30
|
+
// Check for service_role claim
|
|
31
|
+
return payload.role === 'service_role' ||
|
|
32
|
+
(payload.app_metadata && payload.app_metadata.role === 'service_role');
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: 'Supabase Anon Key',
|
|
41
|
+
pattern: /eyJ[A-Za-z0-9-_]*\.eyJ[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*/g,
|
|
42
|
+
severity: 'MEDIUM',
|
|
43
|
+
category: 'supabase',
|
|
44
|
+
description: 'Potential Supabase anon key - verify if properly scoped',
|
|
45
|
+
validator: (match) => {
|
|
46
|
+
const parts = match.split('.');
|
|
47
|
+
if (parts.length !== 3)
|
|
48
|
+
return false;
|
|
49
|
+
try {
|
|
50
|
+
const payload = JSON.parse(Buffer.from(parts[1], 'base64url').toString());
|
|
51
|
+
return payload.role === 'anon' ||
|
|
52
|
+
(payload.app_metadata && payload.app_metadata.role === 'anon');
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
name: 'Supabase URL',
|
|
61
|
+
pattern: /https:\/\/[a-z0-9-]+\.supabase\.co/gi,
|
|
62
|
+
severity: 'INFO',
|
|
63
|
+
category: 'supabase',
|
|
64
|
+
description: 'Supabase project URL detected'
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: 'Service Role Key Variable',
|
|
68
|
+
pattern: /(?:supabase|service)[._-]?role[._-]?key\s*[:=]\s*["\']([^"\']+)["\']/gi,
|
|
69
|
+
severity: 'CRITICAL',
|
|
70
|
+
category: 'supabase',
|
|
71
|
+
description: 'Service role key assignment detected'
|
|
72
|
+
}
|
|
73
|
+
];
|
|
74
|
+
/**
|
|
75
|
+
* Third-party API key patterns
|
|
76
|
+
*/
|
|
77
|
+
exports.apiKeyPatterns = [
|
|
78
|
+
{
|
|
79
|
+
name: 'Stripe Live Key',
|
|
80
|
+
pattern: /sk_live_[0-9a-zA-Z]{24,}/g,
|
|
81
|
+
severity: 'CRITICAL',
|
|
82
|
+
category: 'payment',
|
|
83
|
+
description: 'Stripe live secret key - full account access'
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'Stripe Test Key',
|
|
87
|
+
pattern: /sk_test_[0-9a-zA-Z]{24,}/g,
|
|
88
|
+
severity: 'MEDIUM',
|
|
89
|
+
category: 'payment',
|
|
90
|
+
description: 'Stripe test secret key'
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
name: 'OpenAI API Key',
|
|
94
|
+
pattern: /sk-[a-zA-Z0-9]{48}/g,
|
|
95
|
+
severity: 'CRITICAL',
|
|
96
|
+
category: 'ai',
|
|
97
|
+
description: 'OpenAI API key'
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
name: 'GitHub Personal Access Token',
|
|
101
|
+
pattern: /ghp_[0-9a-zA-Z]{36}/g,
|
|
102
|
+
severity: 'HIGH',
|
|
103
|
+
category: 'vcs',
|
|
104
|
+
description: 'GitHub personal access token'
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
name: 'GitHub OAuth Token',
|
|
108
|
+
pattern: /gho_[0-9a-zA-Z]{36}/g,
|
|
109
|
+
severity: 'HIGH',
|
|
110
|
+
category: 'vcs',
|
|
111
|
+
description: 'GitHub OAuth token'
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
name: 'AWS Access Key ID',
|
|
115
|
+
pattern: /AKIA[0-9A-Z]{16}/g,
|
|
116
|
+
severity: 'CRITICAL',
|
|
117
|
+
category: 'cloud',
|
|
118
|
+
description: 'AWS Access Key ID'
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
name: 'AWS Secret Key',
|
|
122
|
+
pattern: /["\']?(?:aws[_-]?secret[_-]?access[_-]?key|aws_secret)["\']?\s*[:=]\s*["\']([a-zA-Z0-9/+=]{40})["\']/gi,
|
|
123
|
+
severity: 'CRITICAL',
|
|
124
|
+
category: 'cloud',
|
|
125
|
+
description: 'AWS Secret Access Key'
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
name: 'SendGrid API Key',
|
|
129
|
+
pattern: /SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/g,
|
|
130
|
+
severity: 'CRITICAL',
|
|
131
|
+
category: 'email',
|
|
132
|
+
description: 'SendGrid API key'
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
name: 'Twilio API Key',
|
|
136
|
+
pattern: /SK[0-9a-f]{32}/g,
|
|
137
|
+
severity: 'CRITICAL',
|
|
138
|
+
category: 'sms',
|
|
139
|
+
description: 'Twilio API key'
|
|
140
|
+
},
|
|
141
|
+
{
|
|
142
|
+
name: 'Slack Token',
|
|
143
|
+
pattern: /xox[baprs]-[0-9a-zA-Z-]+/g,
|
|
144
|
+
severity: 'HIGH',
|
|
145
|
+
category: 'messaging',
|
|
146
|
+
description: 'Slack bot/user token'
|
|
147
|
+
}
|
|
148
|
+
];
|
|
149
|
+
/**
|
|
150
|
+
* Generic secret patterns
|
|
151
|
+
*/
|
|
152
|
+
exports.genericPatterns = [
|
|
153
|
+
{
|
|
154
|
+
name: 'Generic API Key',
|
|
155
|
+
pattern: /(?:api[_-]?key|apikey|api[_-]?secret)["\']?\s*[:=]\s*["\']([a-zA-Z0-9_\-]{16,})["\']/gi,
|
|
156
|
+
severity: 'HIGH',
|
|
157
|
+
category: 'generic',
|
|
158
|
+
description: 'Generic API key pattern'
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
name: 'Generic Secret',
|
|
162
|
+
pattern: /(?:secret|password|passwd|pwd)["\']?\s*[:=]\s*["\']([^"\']{8,})["\']/gi,
|
|
163
|
+
severity: 'MEDIUM',
|
|
164
|
+
category: 'generic',
|
|
165
|
+
description: 'Generic secret/password pattern'
|
|
166
|
+
},
|
|
167
|
+
{
|
|
168
|
+
name: 'Private Key',
|
|
169
|
+
pattern: /-----BEGIN (RSA |DSA |EC |OPENSSH )?PRIVATE KEY-----/g,
|
|
170
|
+
severity: 'CRITICAL',
|
|
171
|
+
category: 'crypto',
|
|
172
|
+
description: 'Private key detected'
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
name: 'JWT Token',
|
|
176
|
+
pattern: /eyJ[A-Za-z0-9-_]*\.eyJ[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*/g,
|
|
177
|
+
severity: 'HIGH',
|
|
178
|
+
category: 'auth',
|
|
179
|
+
description: 'JWT token detected'
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
name: 'Bearer Token',
|
|
183
|
+
pattern: /Bearer\s+[a-zA-Z0-9_\-\.=]+/g,
|
|
184
|
+
severity: 'HIGH',
|
|
185
|
+
category: 'auth',
|
|
186
|
+
description: 'Bearer token detected'
|
|
187
|
+
}
|
|
188
|
+
];
|
|
189
|
+
/**
|
|
190
|
+
* Environment variable patterns (for .env files)
|
|
191
|
+
*/
|
|
192
|
+
exports.envPatterns = [
|
|
193
|
+
{
|
|
194
|
+
name: 'Env File Secret',
|
|
195
|
+
pattern: /^[A-Z_]*(?:SECRET|KEY|TOKEN|PASSWORD|PWD|API_KEY)[A-Z_]*\s*=\s*(.+)$/gm,
|
|
196
|
+
severity: 'HIGH',
|
|
197
|
+
category: 'config',
|
|
198
|
+
description: 'Secret in environment file'
|
|
199
|
+
}
|
|
200
|
+
];
|
|
201
|
+
/**
|
|
202
|
+
* All patterns combined
|
|
203
|
+
*/
|
|
204
|
+
exports.allPatterns = [
|
|
205
|
+
...exports.supabasePatterns,
|
|
206
|
+
...exports.apiKeyPatterns,
|
|
207
|
+
...exports.genericPatterns,
|
|
208
|
+
...exports.envPatterns
|
|
209
|
+
];
|
|
210
|
+
/**
|
|
211
|
+
* Calculate Shannon entropy of a string
|
|
212
|
+
* Used to detect high-entropy strings that might be secrets
|
|
213
|
+
*/
|
|
214
|
+
function calculateEntropy(str) {
|
|
215
|
+
const len = str.length;
|
|
216
|
+
if (len === 0)
|
|
217
|
+
return 0;
|
|
218
|
+
const freq = {};
|
|
219
|
+
for (const char of str) {
|
|
220
|
+
freq[char] = (freq[char] || 0) + 1;
|
|
221
|
+
}
|
|
222
|
+
let entropy = 0;
|
|
223
|
+
for (const char in freq) {
|
|
224
|
+
const p = freq[char] / len;
|
|
225
|
+
entropy -= p * Math.log2(p);
|
|
226
|
+
}
|
|
227
|
+
return entropy;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Check if a string has high entropy (likely a secret)
|
|
231
|
+
*/
|
|
232
|
+
function hasHighEntropy(str, threshold = 4.5) {
|
|
233
|
+
return calculateEntropy(str) > threshold;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Mask a secret for display
|
|
237
|
+
*/
|
|
238
|
+
function maskSecret(secret, visibleChars = 4) {
|
|
239
|
+
if (secret.length <= visibleChars * 2) {
|
|
240
|
+
return '*'.repeat(secret.length);
|
|
241
|
+
}
|
|
242
|
+
const start = secret.slice(0, visibleChars);
|
|
243
|
+
const end = secret.slice(-visibleChars);
|
|
244
|
+
const middle = '*'.repeat(secret.length - visibleChars * 2);
|
|
245
|
+
return `${start}${middle}${end}`;
|
|
246
|
+
}
|
|
247
|
+
function detectSecrets(content, patterns = exports.allPatterns) {
|
|
248
|
+
const findings = [];
|
|
249
|
+
const lines = content.split('\n');
|
|
250
|
+
for (const pattern of patterns) {
|
|
251
|
+
// Reset regex lastIndex
|
|
252
|
+
pattern.pattern.lastIndex = 0;
|
|
253
|
+
let match;
|
|
254
|
+
while ((match = pattern.pattern.exec(content)) !== null) {
|
|
255
|
+
const matchedText = match[0];
|
|
256
|
+
const matchIndex = match.index;
|
|
257
|
+
// Validate if validator exists
|
|
258
|
+
if (pattern.validator && !pattern.validator(matchedText)) {
|
|
259
|
+
continue;
|
|
260
|
+
}
|
|
261
|
+
// Find line and column
|
|
262
|
+
let line = 1;
|
|
263
|
+
let column = 1;
|
|
264
|
+
let currentIndex = 0;
|
|
265
|
+
for (let i = 0; i < lines.length; i++) {
|
|
266
|
+
const lineLength = lines[i].length + 1; // +1 for newline
|
|
267
|
+
if (currentIndex + lineLength > matchIndex) {
|
|
268
|
+
line = i + 1;
|
|
269
|
+
column = matchIndex - currentIndex + 1;
|
|
270
|
+
break;
|
|
271
|
+
}
|
|
272
|
+
currentIndex += lineLength;
|
|
273
|
+
}
|
|
274
|
+
findings.push({
|
|
275
|
+
pattern,
|
|
276
|
+
match: matchedText,
|
|
277
|
+
line,
|
|
278
|
+
column,
|
|
279
|
+
masked: maskSecret(matchedText)
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return findings;
|
|
284
|
+
}
|
|
285
|
+
//# sourceMappingURL=patterns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../../src/scanners/secrets/patterns.ts"],"names":[],"mappings":"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"}
|