bastion-scan 0.1.2 → 0.1.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/README.md +1 -1
- package/dist/index.js +117 -12
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ npx bastion-scan scan --generate-configs
|
|
|
48
48
|
| Check | What it does |
|
|
49
49
|
|-------|-------------|
|
|
50
50
|
| `.gitignore` coverage | Makes sure `.env`, `node_modules`, and keys are excluded |
|
|
51
|
-
| Hardcoded secrets |
|
|
51
|
+
| Hardcoded secrets | API keys from OpenAI, Anthropic, GitHub, Stripe, AWS, Google, Slack, and more |
|
|
52
52
|
| Dependency audit | Wraps `npm audit` and maps findings to severity levels |
|
|
53
53
|
| `.env.example` | Checks that a template exists with safe placeholder values |
|
|
54
54
|
| `security.txt` | Validates RFC 9116 Contact + Expires fields |
|
package/dist/index.js
CHANGED
|
@@ -196,40 +196,145 @@ var SCANNABLE_EXTENSIONS = /* @__PURE__ */ new Set([
|
|
|
196
196
|
]);
|
|
197
197
|
var IGNORED_DIRS = /* @__PURE__ */ new Set(["node_modules", "dist", "build", ".git", "tests", "__tests__", "test", "fixtures"]);
|
|
198
198
|
var SECRET_PATTERNS = [
|
|
199
|
+
// ── OpenAI ──────────────────────────────────────────────────────────────
|
|
199
200
|
{
|
|
200
|
-
name: "OpenAI API key",
|
|
201
|
-
regex: /sk-[
|
|
202
|
-
description: "OpenAI API key detected"
|
|
201
|
+
name: "OpenAI API key (project)",
|
|
202
|
+
regex: /sk-proj-[a-zA-Z0-9_-]{20,}/,
|
|
203
|
+
description: "OpenAI project API key detected",
|
|
204
|
+
severity: "critical"
|
|
203
205
|
},
|
|
206
|
+
{
|
|
207
|
+
name: "OpenAI API key (service account)",
|
|
208
|
+
regex: /sk-svcacct-[a-zA-Z0-9_-]{20,}/,
|
|
209
|
+
description: "OpenAI service account key detected",
|
|
210
|
+
severity: "critical"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
name: "OpenAI API key (legacy)",
|
|
214
|
+
regex: /sk-[a-zA-Z0-9]{20,}/,
|
|
215
|
+
description: "OpenAI API key detected",
|
|
216
|
+
severity: "critical"
|
|
217
|
+
},
|
|
218
|
+
// ── Anthropic ───────────────────────────────────────────────────────────
|
|
219
|
+
{
|
|
220
|
+
name: "Anthropic API key",
|
|
221
|
+
regex: /sk-ant-api[0-9]{2}-[a-zA-Z0-9_-]{40,}/,
|
|
222
|
+
description: "Anthropic API key detected",
|
|
223
|
+
severity: "critical"
|
|
224
|
+
},
|
|
225
|
+
{
|
|
226
|
+
name: "Anthropic admin key",
|
|
227
|
+
regex: /sk-ant-admin[0-9]{2}-[a-zA-Z0-9_-]{40,}/,
|
|
228
|
+
description: "Anthropic admin API key detected",
|
|
229
|
+
severity: "critical"
|
|
230
|
+
},
|
|
231
|
+
// ── GitHub ──────────────────────────────────────────────────────────────
|
|
232
|
+
{
|
|
233
|
+
name: "GitHub PAT (classic)",
|
|
234
|
+
regex: /ghp_[a-zA-Z0-9]{36}/,
|
|
235
|
+
description: "GitHub personal access token (classic) detected",
|
|
236
|
+
severity: "critical"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
name: "GitHub OAuth token",
|
|
240
|
+
regex: /gho_[a-zA-Z0-9]{36}/,
|
|
241
|
+
description: "GitHub OAuth access token detected",
|
|
242
|
+
severity: "critical"
|
|
243
|
+
},
|
|
244
|
+
{
|
|
245
|
+
name: "GitHub PAT (fine-grained)",
|
|
246
|
+
regex: /github_pat_[a-zA-Z0-9_]{82}/,
|
|
247
|
+
description: "GitHub fine-grained personal access token detected",
|
|
248
|
+
severity: "critical"
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
name: "GitHub app token",
|
|
252
|
+
regex: /ghs_[a-zA-Z0-9]{36}/,
|
|
253
|
+
description: "GitHub app installation token detected",
|
|
254
|
+
severity: "critical"
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
name: "GitHub refresh token",
|
|
258
|
+
regex: /ghr_[a-zA-Z0-9]{36}/,
|
|
259
|
+
description: "GitHub refresh token detected",
|
|
260
|
+
severity: "critical"
|
|
261
|
+
},
|
|
262
|
+
// ── Stripe ──────────────────────────────────────────────────────────────
|
|
204
263
|
{
|
|
205
264
|
name: "Stripe secret key",
|
|
206
|
-
regex: /sk_live_[
|
|
207
|
-
description: "Stripe secret key detected"
|
|
265
|
+
regex: /sk_live_[a-zA-Z0-9]{24,}/,
|
|
266
|
+
description: "Stripe secret key detected",
|
|
267
|
+
severity: "critical"
|
|
208
268
|
},
|
|
209
269
|
{
|
|
210
270
|
name: "Stripe publishable key",
|
|
211
|
-
regex: /pk_live_[
|
|
212
|
-
description: "Stripe publishable live key detected"
|
|
271
|
+
regex: /pk_live_[a-zA-Z0-9]{20,}/,
|
|
272
|
+
description: "Stripe publishable live key detected",
|
|
273
|
+
severity: "critical"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
name: "Stripe restricted key",
|
|
277
|
+
regex: /rk_live_[a-zA-Z0-9]{24,}/,
|
|
278
|
+
description: "Stripe restricted API key detected",
|
|
279
|
+
severity: "critical"
|
|
213
280
|
},
|
|
281
|
+
{
|
|
282
|
+
name: "Stripe test key",
|
|
283
|
+
regex: /sk_test_[a-zA-Z0-9]{24,}/,
|
|
284
|
+
description: "Stripe test secret key detected",
|
|
285
|
+
severity: "high"
|
|
286
|
+
},
|
|
287
|
+
// ── AWS ─────────────────────────────────────────────────────────────────
|
|
214
288
|
{
|
|
215
289
|
name: "AWS access key",
|
|
216
290
|
regex: /AKIA[0-9A-Z]{16}/,
|
|
217
|
-
description: "AWS access key ID detected"
|
|
291
|
+
description: "AWS access key ID detected",
|
|
292
|
+
severity: "critical"
|
|
293
|
+
},
|
|
294
|
+
// ── Google ──────────────────────────────────────────────────────────────
|
|
295
|
+
{
|
|
296
|
+
name: "Google API key",
|
|
297
|
+
regex: /AIza[a-zA-Z0-9_-]{35}/,
|
|
298
|
+
description: "Google API key detected",
|
|
299
|
+
severity: "critical"
|
|
218
300
|
},
|
|
301
|
+
// ── Slack ───────────────────────────────────────────────────────────────
|
|
302
|
+
{
|
|
303
|
+
name: "Slack bot token",
|
|
304
|
+
regex: /xoxb-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{24,}/,
|
|
305
|
+
description: "Slack bot token detected",
|
|
306
|
+
severity: "critical"
|
|
307
|
+
},
|
|
308
|
+
{
|
|
309
|
+
name: "Slack user token",
|
|
310
|
+
regex: /xoxp-[0-9]{10,13}-[0-9]{10,13}-[0-9]{10,13}-[a-zA-Z0-9]{32}/,
|
|
311
|
+
description: "Slack user token detected",
|
|
312
|
+
severity: "critical"
|
|
313
|
+
},
|
|
314
|
+
{
|
|
315
|
+
name: "Slack webhook URL",
|
|
316
|
+
regex: /https:\/\/hooks\.slack\.com\/services\/T[a-zA-Z0-9]{8,12}\/B[a-zA-Z0-9]{8,12}\/[a-zA-Z0-9]{24}/,
|
|
317
|
+
description: "Slack incoming webhook URL detected",
|
|
318
|
+
severity: "high"
|
|
319
|
+
},
|
|
320
|
+
// ── Generic ─────────────────────────────────────────────────────────────
|
|
219
321
|
{
|
|
220
322
|
name: "Generic API key assignment",
|
|
221
323
|
regex: /(?:api[_-]?key|apikey|api[_-]?secret)\s*[:=]\s*['"][A-Za-z0-9_\-/.]{8,}['"]/i,
|
|
222
|
-
description: "Hardcoded API key assignment detected"
|
|
324
|
+
description: "Hardcoded API key assignment detected",
|
|
325
|
+
severity: "critical"
|
|
223
326
|
},
|
|
224
327
|
{
|
|
225
328
|
name: "Bearer token",
|
|
226
329
|
regex: /['"]Bearer\s+[A-Za-z0-9_\-/.+]{20,}['"]/,
|
|
227
|
-
description: "Hardcoded Bearer token detected"
|
|
330
|
+
description: "Hardcoded Bearer token detected",
|
|
331
|
+
severity: "critical"
|
|
228
332
|
},
|
|
229
333
|
{
|
|
230
334
|
name: "Database connection string",
|
|
231
335
|
regex: /(?:mongodb(?:\+srv)?|postgres(?:ql)?|mysql|redis):\/\/[^:]+:[^@\s]+@/i,
|
|
232
|
-
description: "Database connection string with embedded password detected"
|
|
336
|
+
description: "Database connection string with embedded password detected",
|
|
337
|
+
severity: "critical"
|
|
233
338
|
}
|
|
234
339
|
];
|
|
235
340
|
var AI_PROMPT = "I found a hardcoded secret in my source code. Help me move it to an environment variable. Show me: (1) how to add it to .env, (2) how to read it with process.env or the equivalent for my framework, (3) how to add the key name to .env.example with a placeholder value, and (4) how to validate at startup that the variable is set.";
|
|
@@ -265,7 +370,7 @@ function scanContent(content, relativePath) {
|
|
|
265
370
|
id: "secrets",
|
|
266
371
|
name: `Hardcoded secret: ${pattern.name}`,
|
|
267
372
|
status: "fail",
|
|
268
|
-
severity:
|
|
373
|
+
severity: pattern.severity,
|
|
269
374
|
category: "Secrets",
|
|
270
375
|
location: `${relativePath}:${i + 1}`,
|
|
271
376
|
description: pattern.description,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bastion-scan",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Privacy-first security checker for web projects. 15 checks, zero data uploaded, actionable fixes.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"dev": "tsup --watch"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"bastion-shared": "^0.1.
|
|
40
|
+
"bastion-shared": "^0.1.3",
|
|
41
41
|
"chalk": "^5.6.2",
|
|
42
42
|
"commander": "^14.0.3",
|
|
43
43
|
"ora": "^9.3.0"
|