bilt-toolkit 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/LICENSE +0 -0
- package/README.md +168 -0
- package/bin/bilt.js +2 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +161 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +13 -0
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/commands/doctor.js +194 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/fix.d.ts +12 -0
- package/dist/commands/fix.d.ts.map +1 -0
- package/dist/commands/fix.js +273 -0
- package/dist/commands/fix.js.map +1 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +101 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/scan.d.ts +17 -0
- package/dist/commands/scan.d.ts.map +1 -0
- package/dist/commands/scan.js +267 -0
- package/dist/commands/scan.js.map +1 -0
- package/dist/commands/undo.d.ts +12 -0
- package/dist/commands/undo.d.ts.map +1 -0
- package/dist/commands/undo.js +90 -0
- package/dist/commands/undo.js.map +1 -0
- package/dist/commands/watch.d.ts +10 -0
- package/dist/commands/watch.d.ts.map +1 -0
- package/dist/commands/watch.js +68 -0
- package/dist/commands/watch.js.map +1 -0
- package/dist/config/config.d.ts +8 -0
- package/dist/config/config.d.ts.map +1 -0
- package/dist/config/config.js +75 -0
- package/dist/config/config.js.map +1 -0
- package/dist/core/fix/confirm.d.ts +21 -0
- package/dist/core/fix/confirm.d.ts.map +1 -0
- package/dist/core/fix/confirm.js +60 -0
- package/dist/core/fix/confirm.js.map +1 -0
- package/dist/core/fix/env-fix.d.ts +40 -0
- package/dist/core/fix/env-fix.d.ts.map +1 -0
- package/dist/core/fix/env-fix.js +186 -0
- package/dist/core/fix/env-fix.js.map +1 -0
- package/dist/core/fix/snapshot.d.ts +30 -0
- package/dist/core/fix/snapshot.d.ts.map +1 -0
- package/dist/core/fix/snapshot.js +186 -0
- package/dist/core/fix/snapshot.js.map +1 -0
- package/dist/core/rules/entropy.d.ts +29 -0
- package/dist/core/rules/entropy.d.ts.map +1 -0
- package/dist/core/rules/entropy.js +117 -0
- package/dist/core/rules/entropy.js.map +1 -0
- package/dist/core/rules/providers.d.ts +12 -0
- package/dist/core/rules/providers.d.ts.map +1 -0
- package/dist/core/rules/providers.js +184 -0
- package/dist/core/rules/providers.js.map +1 -0
- package/dist/core/rules/secret-rules.d.ts +3 -0
- package/dist/core/rules/secret-rules.d.ts.map +1 -0
- package/dist/core/rules/secret-rules.js +205 -0
- package/dist/core/rules/secret-rules.js.map +1 -0
- package/dist/core/scan/env.d.ts +47 -0
- package/dist/core/scan/env.d.ts.map +1 -0
- package/dist/core/scan/env.js +301 -0
- package/dist/core/scan/env.js.map +1 -0
- package/dist/core/scan/framework.d.ts +26 -0
- package/dist/core/scan/framework.d.ts.map +1 -0
- package/dist/core/scan/framework.js +254 -0
- package/dist/core/scan/framework.js.map +1 -0
- package/dist/core/scan/gitignore.d.ts +20 -0
- package/dist/core/scan/gitignore.d.ts.map +1 -0
- package/dist/core/scan/gitignore.js +217 -0
- package/dist/core/scan/gitignore.js.map +1 -0
- package/dist/core/scan/secrets.d.ts +27 -0
- package/dist/core/scan/secrets.d.ts.map +1 -0
- package/dist/core/scan/secrets.js +247 -0
- package/dist/core/scan/secrets.js.map +1 -0
- package/dist/core/score/health.d.ts +29 -0
- package/dist/core/score/health.d.ts.map +1 -0
- package/dist/core/score/health.js +73 -0
- package/dist/core/score/health.js.map +1 -0
- package/dist/core/watch/watcher.d.ts +29 -0
- package/dist/core/watch/watcher.d.ts.map +1 -0
- package/dist/core/watch/watcher.js +176 -0
- package/dist/core/watch/watcher.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/plugins/interface.d.ts +12 -0
- package/dist/plugins/interface.d.ts.map +1 -0
- package/dist/plugins/interface.js +91 -0
- package/dist/plugins/interface.js.map +1 -0
- package/dist/plugins/loader.d.ts +10 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +104 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/plugins/official/docker.d.ts +4 -0
- package/dist/plugins/official/docker.d.ts.map +1 -0
- package/dist/plugins/official/docker.js +111 -0
- package/dist/plugins/official/docker.js.map +1 -0
- package/dist/plugins/official/terraform.d.ts +4 -0
- package/dist/plugins/official/terraform.d.ts.map +1 -0
- package/dist/plugins/official/terraform.js +131 -0
- package/dist/plugins/official/terraform.js.map +1 -0
- package/dist/types/index.d.ts +158 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +3 -0
- package/dist/types/index.js.map +1 -0
- package/dist/ui/format.d.ts +43 -0
- package/dist/ui/format.d.ts.map +1 -0
- package/dist/ui/format.js +207 -0
- package/dist/ui/format.js.map +1 -0
- package/dist/ui/reporter.d.ts +39 -0
- package/dist/ui/reporter.d.ts.map +1 -0
- package/dist/ui/reporter.js +254 -0
- package/dist/ui/reporter.js.map +1 -0
- package/package.json +65 -0
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// ─── Shannon Entropy Utilities ───────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Pure functions for calculating Shannon entropy of string values.
|
|
4
|
+
// Used by secret-detection rules to flag high-entropy values that are
|
|
5
|
+
// likely API keys, tokens, or passwords even when no regex rule matches.
|
|
6
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
/** Minimum value length considered for entropy analysis. */
|
|
8
|
+
const MIN_LENGTH = 8;
|
|
9
|
+
/**
|
|
10
|
+
* UUID v4 pattern — values that match are skipped because UUIDs are
|
|
11
|
+
* high-entropy by design but are almost never secrets.
|
|
12
|
+
*/
|
|
13
|
+
const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
14
|
+
/**
|
|
15
|
+
* Common English / config words that happen to be long-ish but are
|
|
16
|
+
* obviously not secrets. All comparisons are lower-cased.
|
|
17
|
+
*/
|
|
18
|
+
const COMMON_WORDS = new Set([
|
|
19
|
+
"development",
|
|
20
|
+
"production",
|
|
21
|
+
"staging",
|
|
22
|
+
"localhost",
|
|
23
|
+
"undefined",
|
|
24
|
+
"password",
|
|
25
|
+
"username",
|
|
26
|
+
"database",
|
|
27
|
+
"hostname",
|
|
28
|
+
"application",
|
|
29
|
+
"configuration",
|
|
30
|
+
"environment",
|
|
31
|
+
"true",
|
|
32
|
+
"false",
|
|
33
|
+
"null",
|
|
34
|
+
"enabled",
|
|
35
|
+
"disabled",
|
|
36
|
+
"default",
|
|
37
|
+
"example",
|
|
38
|
+
"changeme",
|
|
39
|
+
"change_me",
|
|
40
|
+
"your-api-key",
|
|
41
|
+
"your-api-key-here",
|
|
42
|
+
"your_api_key",
|
|
43
|
+
"your_api_key_here",
|
|
44
|
+
"replace_me",
|
|
45
|
+
"replaceme",
|
|
46
|
+
"placeholder",
|
|
47
|
+
"test1234",
|
|
48
|
+
"testtest",
|
|
49
|
+
"abcdefgh",
|
|
50
|
+
"xxxxxxxx",
|
|
51
|
+
"todo",
|
|
52
|
+
"fixme",
|
|
53
|
+
]);
|
|
54
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
55
|
+
/**
|
|
56
|
+
* Calculate the Shannon entropy (in bits-per-character) of a string.
|
|
57
|
+
*
|
|
58
|
+
* Shannon entropy is defined as:
|
|
59
|
+
* H = -Σ p(x) · log₂(p(x))
|
|
60
|
+
*
|
|
61
|
+
* where p(x) is the frequency of character x in the string.
|
|
62
|
+
*
|
|
63
|
+
* Higher values indicate more randomness — typical English prose scores
|
|
64
|
+
* around 3.5–4.0 while random hex/base64 strings score 4.5–6.0+.
|
|
65
|
+
*/
|
|
66
|
+
export function calculateShannonEntropy(value) {
|
|
67
|
+
if (value.length === 0)
|
|
68
|
+
return 0;
|
|
69
|
+
// Build frequency map
|
|
70
|
+
const freq = new Map();
|
|
71
|
+
for (const ch of value) {
|
|
72
|
+
freq.set(ch, (freq.get(ch) ?? 0) + 1);
|
|
73
|
+
}
|
|
74
|
+
const len = value.length;
|
|
75
|
+
let entropy = 0;
|
|
76
|
+
for (const count of freq.values()) {
|
|
77
|
+
const p = count / len;
|
|
78
|
+
// p is always > 0 here, so log₂ is safe
|
|
79
|
+
entropy -= p * Math.log2(p);
|
|
80
|
+
}
|
|
81
|
+
return entropy;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Determine whether a value is "high entropy" — i.e. random enough to
|
|
85
|
+
* plausibly be a secret key / token.
|
|
86
|
+
*
|
|
87
|
+
* Before running the entropy check the function applies several
|
|
88
|
+
* heuristics to avoid false positives:
|
|
89
|
+
*
|
|
90
|
+
* 1. Values shorter than 8 characters are skipped (too short to be a key).
|
|
91
|
+
* 2. Pure UUID strings are skipped (high-entropy but not secret).
|
|
92
|
+
* 3. Values that match common configuration words are skipped.
|
|
93
|
+
*
|
|
94
|
+
* @param value The raw string value to analyse.
|
|
95
|
+
* @param threshold Minimum entropy (bits-per-char) to be considered
|
|
96
|
+
* "high". Defaults to **4.5**.
|
|
97
|
+
*/
|
|
98
|
+
export function isHighEntropy(value, threshold = 4.5) {
|
|
99
|
+
// ── fast-exit filters ──────────────────────────────────────────────
|
|
100
|
+
if (value.length < MIN_LENGTH)
|
|
101
|
+
return false;
|
|
102
|
+
if (UUID_RE.test(value))
|
|
103
|
+
return false;
|
|
104
|
+
if (COMMON_WORDS.has(value.toLowerCase()))
|
|
105
|
+
return false;
|
|
106
|
+
// Skip values that are all the same character (e.g. "xxxxxxxx")
|
|
107
|
+
if (new Set(value).size === 1)
|
|
108
|
+
return false;
|
|
109
|
+
// Skip values that look like repeated short patterns (e.g. "abababab")
|
|
110
|
+
if (value.length >= 8) {
|
|
111
|
+
const half = value.slice(0, Math.floor(value.length / 2));
|
|
112
|
+
if (value === half + half)
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return calculateShannonEntropy(value) >= threshold;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=entropy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entropy.js","sourceRoot":"","sources":["../../../src/core/rules/entropy.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,EAAE;AACF,mEAAmE;AACnE,sEAAsE;AACtE,yEAAyE;AACzE,gFAAgF;AAEhF,4DAA4D;AAC5D,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB;;;GAGG;AACH,MAAM,OAAO,GACX,4EAA4E,CAAC;AAE/E;;;GAGG;AACH,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;IAC3B,aAAa;IACb,YAAY;IACZ,SAAS;IACT,WAAW;IACX,WAAW;IACX,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,aAAa;IACb,eAAe;IACf,aAAa;IACb,MAAM;IACN,OAAO;IACP,MAAM;IACN,SAAS;IACT,UAAU;IACV,SAAS;IACT,SAAS;IACT,UAAU;IACV,WAAW;IACX,cAAc;IACd,mBAAmB;IACnB,cAAc;IACd,mBAAmB;IACnB,YAAY;IACZ,WAAW;IACX,aAAa;IACb,UAAU;IACV,UAAU;IACV,UAAU;IACV,UAAU;IACV,MAAM;IACN,OAAO;CACR,CAAC,CAAC;AAEH,gFAAgF;AAEhF;;;;;;;;;;GAUG;AACH,MAAM,UAAU,uBAAuB,CAAC,KAAa;IACnD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAEjC,sBAAsB;IACtB,MAAM,IAAI,GAAG,IAAI,GAAG,EAAkB,CAAC;IACvC,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC;IACzB,IAAI,OAAO,GAAG,CAAC,CAAC;IAEhB,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;QAClC,MAAM,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC;QACtB,wCAAwC;QACxC,OAAO,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,SAAS,GAAG,GAAG;IAC1D,sEAAsE;IACtE,IAAI,KAAK,CAAC,MAAM,GAAG,UAAU;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACtC,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QAAE,OAAO,KAAK,CAAC;IAExD,gEAAgE;IAChE,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAE5C,uEAAuE;IACvE,IAAI,KAAK,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;QAC1D,IAAI,KAAK,KAAK,IAAI,GAAG,IAAI;YAAE,OAAO,KAAK,CAAC;IAC1C,CAAC;IAED,OAAO,uBAAuB,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC;AACrD,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ProviderInfo } from "../../types/index.js";
|
|
2
|
+
export declare const PROVIDER_MAP: Map<string, ProviderInfo>;
|
|
3
|
+
/**
|
|
4
|
+
* Attempt to identify which cloud provider a secret value belongs to.
|
|
5
|
+
*
|
|
6
|
+
* Resolution order:
|
|
7
|
+
* 1. If a `matchedRuleId` is supplied and maps to a known provider, use that.
|
|
8
|
+
* 2. Walk value-based heuristics (prefix / substring checks).
|
|
9
|
+
* 3. Return `undefined` if the provider cannot be determined.
|
|
10
|
+
*/
|
|
11
|
+
export declare function detectProvider(value: string, matchedRuleId?: string): ProviderInfo | undefined;
|
|
12
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.d.ts","sourceRoot":"","sources":["../../../src/core/rules/providers.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAiHzD,eAAO,MAAM,YAAY,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAcjD,CAAC;AAqDH;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,MAAM,EACb,aAAa,CAAC,EAAE,MAAM,GACrB,YAAY,GAAG,SAAS,CAiB1B"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
// ─── Provider Information & Detection ────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// Maps cloud / SaaS providers to their credential-management pages
|
|
4
|
+
// so that Bilt can tell developers exactly where to rotate a leaked key.
|
|
5
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
// ─── Provider Definitions ────────────────────────────────────────────────────
|
|
7
|
+
const aws = {
|
|
8
|
+
name: "aws",
|
|
9
|
+
displayName: "Amazon Web Services",
|
|
10
|
+
icon: "☁️",
|
|
11
|
+
rotationUrl: "https://console.aws.amazon.com/iam/home#/security_credentials",
|
|
12
|
+
docsUrl: "https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html",
|
|
13
|
+
};
|
|
14
|
+
const stripe = {
|
|
15
|
+
name: "stripe",
|
|
16
|
+
displayName: "Stripe",
|
|
17
|
+
icon: "💳",
|
|
18
|
+
rotationUrl: "https://dashboard.stripe.com/apikeys",
|
|
19
|
+
docsUrl: "https://docs.stripe.com/keys",
|
|
20
|
+
};
|
|
21
|
+
const openai = {
|
|
22
|
+
name: "openai",
|
|
23
|
+
displayName: "OpenAI",
|
|
24
|
+
icon: "🤖",
|
|
25
|
+
rotationUrl: "https://platform.openai.com/api-keys",
|
|
26
|
+
docsUrl: "https://platform.openai.com/docs/api-reference/authentication",
|
|
27
|
+
};
|
|
28
|
+
const github = {
|
|
29
|
+
name: "github",
|
|
30
|
+
displayName: "GitHub",
|
|
31
|
+
icon: "🐙",
|
|
32
|
+
rotationUrl: "https://github.com/settings/tokens",
|
|
33
|
+
docsUrl: "https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens",
|
|
34
|
+
};
|
|
35
|
+
const supabase = {
|
|
36
|
+
name: "supabase",
|
|
37
|
+
displayName: "Supabase",
|
|
38
|
+
icon: "⚡",
|
|
39
|
+
rotationUrl: "https://app.supabase.com/project/_/settings/api",
|
|
40
|
+
docsUrl: "https://supabase.com/docs/guides/api#api-keys",
|
|
41
|
+
};
|
|
42
|
+
const slack = {
|
|
43
|
+
name: "slack",
|
|
44
|
+
displayName: "Slack",
|
|
45
|
+
icon: "💬",
|
|
46
|
+
rotationUrl: "https://api.slack.com/apps",
|
|
47
|
+
docsUrl: "https://api.slack.com/authentication/token-types",
|
|
48
|
+
};
|
|
49
|
+
const google = {
|
|
50
|
+
name: "google",
|
|
51
|
+
displayName: "Google Cloud",
|
|
52
|
+
icon: "🔍",
|
|
53
|
+
rotationUrl: "https://console.cloud.google.com/apis/credentials",
|
|
54
|
+
docsUrl: "https://cloud.google.com/docs/authentication/api-keys",
|
|
55
|
+
};
|
|
56
|
+
const twilio = {
|
|
57
|
+
name: "twilio",
|
|
58
|
+
displayName: "Twilio",
|
|
59
|
+
icon: "📞",
|
|
60
|
+
rotationUrl: "https://www.twilio.com/console",
|
|
61
|
+
docsUrl: "https://www.twilio.com/docs/iam/api-keys",
|
|
62
|
+
};
|
|
63
|
+
const sendgrid = {
|
|
64
|
+
name: "sendgrid",
|
|
65
|
+
displayName: "SendGrid",
|
|
66
|
+
icon: "📧",
|
|
67
|
+
rotationUrl: "https://app.sendgrid.com/settings/api_keys",
|
|
68
|
+
docsUrl: "https://docs.sendgrid.com/ui/account-and-settings/api-keys",
|
|
69
|
+
};
|
|
70
|
+
const mailgun = {
|
|
71
|
+
name: "mailgun",
|
|
72
|
+
displayName: "Mailgun",
|
|
73
|
+
icon: "📬",
|
|
74
|
+
rotationUrl: "https://app.mailgun.com/app/account/security/api_keys",
|
|
75
|
+
docsUrl: "https://documentation.mailgun.com/en/latest/api-intro.html",
|
|
76
|
+
};
|
|
77
|
+
const mailchimp = {
|
|
78
|
+
name: "mailchimp",
|
|
79
|
+
displayName: "Mailchimp",
|
|
80
|
+
icon: "🐵",
|
|
81
|
+
rotationUrl: "https://us1.admin.mailchimp.com/account/api/",
|
|
82
|
+
docsUrl: "https://mailchimp.com/developer/marketing/guides/quick-start/",
|
|
83
|
+
};
|
|
84
|
+
const heroku = {
|
|
85
|
+
name: "heroku",
|
|
86
|
+
displayName: "Heroku",
|
|
87
|
+
icon: "🟣",
|
|
88
|
+
rotationUrl: "https://dashboard.heroku.com/account",
|
|
89
|
+
docsUrl: "https://devcenter.heroku.com/articles/authentication",
|
|
90
|
+
};
|
|
91
|
+
const digitalocean = {
|
|
92
|
+
name: "digitalocean",
|
|
93
|
+
displayName: "DigitalOcean",
|
|
94
|
+
icon: "🌊",
|
|
95
|
+
rotationUrl: "https://cloud.digitalocean.com/account/api/tokens",
|
|
96
|
+
docsUrl: "https://docs.digitalocean.com/reference/api/create-personal-access-token/",
|
|
97
|
+
};
|
|
98
|
+
// ─── Provider Map ────────────────────────────────────────────────────────────
|
|
99
|
+
export const PROVIDER_MAP = new Map([
|
|
100
|
+
["aws", aws],
|
|
101
|
+
["stripe", stripe],
|
|
102
|
+
["openai", openai],
|
|
103
|
+
["github", github],
|
|
104
|
+
["supabase", supabase],
|
|
105
|
+
["slack", slack],
|
|
106
|
+
["google", google],
|
|
107
|
+
["twilio", twilio],
|
|
108
|
+
["sendgrid", sendgrid],
|
|
109
|
+
["mailgun", mailgun],
|
|
110
|
+
["mailchimp", mailchimp],
|
|
111
|
+
["heroku", heroku],
|
|
112
|
+
["digitalocean", digitalocean],
|
|
113
|
+
]);
|
|
114
|
+
// ─── Value-based detection heuristics ────────────────────────────────────────
|
|
115
|
+
// Maps a substring / prefix found in the matched value to a provider name.
|
|
116
|
+
const VALUE_HINTS = [
|
|
117
|
+
{ test: (v) => v.startsWith("AKIA"), provider: "aws" },
|
|
118
|
+
{ test: (v) => /^sk_(live|test)_/.test(v), provider: "stripe" },
|
|
119
|
+
{ test: (v) => /^pk_(live|test)_/.test(v), provider: "stripe" },
|
|
120
|
+
{ test: (v) => /^rk_(live|test)_/.test(v), provider: "stripe" },
|
|
121
|
+
{ test: (v) => v.startsWith("sk-"), provider: "openai" },
|
|
122
|
+
{ test: (v) => /^gh[pousr]_/.test(v), provider: "github" },
|
|
123
|
+
{ test: (v) => /^xox[bps]-/.test(v), provider: "slack" },
|
|
124
|
+
{ test: (v) => v.includes("hooks.slack.com"), provider: "slack" },
|
|
125
|
+
{ test: (v) => v.startsWith("AIza"), provider: "google" },
|
|
126
|
+
{
|
|
127
|
+
test: (v) => v.startsWith("SK") && /^SK[0-9a-fA-F]{32}$/.test(v),
|
|
128
|
+
provider: "twilio",
|
|
129
|
+
},
|
|
130
|
+
{ test: (v) => v.startsWith("SG."), provider: "sendgrid" },
|
|
131
|
+
{ test: (v) => v.startsWith("sbp_"), provider: "supabase" },
|
|
132
|
+
{ test: (v) => v.startsWith("key-"), provider: "mailgun" },
|
|
133
|
+
{ test: (v) => /-us\d{1,2}$/.test(v), provider: "mailchimp" },
|
|
134
|
+
{ test: (v) => v.startsWith("dop_v1_"), provider: "digitalocean" },
|
|
135
|
+
];
|
|
136
|
+
// ─── Rule-ID to provider mapping ────────────────────────────────────────────
|
|
137
|
+
// Extracted from the rule definitions so we can resolve by ID without
|
|
138
|
+
// needing to re-import the rules (avoids circular deps).
|
|
139
|
+
const RULE_ID_PROVIDER = {
|
|
140
|
+
"aws-access-key": "aws",
|
|
141
|
+
"aws-secret-key": "aws",
|
|
142
|
+
"stripe-secret-key": "stripe",
|
|
143
|
+
"stripe-test-secret-key": "stripe",
|
|
144
|
+
"stripe-publishable-key": "stripe",
|
|
145
|
+
"stripe-restricted-key": "stripe",
|
|
146
|
+
"openai-api-key": "openai",
|
|
147
|
+
"github-token": "github",
|
|
148
|
+
"slack-token": "slack",
|
|
149
|
+
"slack-webhook": "slack",
|
|
150
|
+
"google-api-key": "google",
|
|
151
|
+
"twilio-api-key": "twilio",
|
|
152
|
+
"sendgrid-api-key": "sendgrid",
|
|
153
|
+
"supabase-service-key": "supabase",
|
|
154
|
+
"mailgun-api-key": "mailgun",
|
|
155
|
+
"mailchimp-api-key": "mailchimp",
|
|
156
|
+
"heroku-api-key": "heroku",
|
|
157
|
+
"digitalocean-token": "digitalocean",
|
|
158
|
+
};
|
|
159
|
+
// ─── Public API ──────────────────────────────────────────────────────────────
|
|
160
|
+
/**
|
|
161
|
+
* Attempt to identify which cloud provider a secret value belongs to.
|
|
162
|
+
*
|
|
163
|
+
* Resolution order:
|
|
164
|
+
* 1. If a `matchedRuleId` is supplied and maps to a known provider, use that.
|
|
165
|
+
* 2. Walk value-based heuristics (prefix / substring checks).
|
|
166
|
+
* 3. Return `undefined` if the provider cannot be determined.
|
|
167
|
+
*/
|
|
168
|
+
export function detectProvider(value, matchedRuleId) {
|
|
169
|
+
// 1. Try rule-ID lookup first (most reliable)
|
|
170
|
+
if (matchedRuleId) {
|
|
171
|
+
const providerName = RULE_ID_PROVIDER[matchedRuleId];
|
|
172
|
+
if (providerName) {
|
|
173
|
+
return PROVIDER_MAP.get(providerName);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
// 2. Value-based heuristics
|
|
177
|
+
for (const hint of VALUE_HINTS) {
|
|
178
|
+
if (hint.test(value)) {
|
|
179
|
+
return PROVIDER_MAP.get(hint.provider);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../../src/core/rules/providers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-rules.d.ts","sourceRoot":"","sources":["../../../src/core/rules/secret-rules.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,eAAO,MAAM,YAAY,EAAE,UAAU,EAqNpC,CAAC"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
// ─── Secret Detection Rules ──────────────────────────────────────────────────
|
|
2
|
+
//
|
|
3
|
+
// A curated list of regex-based rules for detecting leaked secrets,
|
|
4
|
+
// API keys, tokens, and credentials in source code and .env files.
|
|
5
|
+
//
|
|
6
|
+
// Each rule specifies:
|
|
7
|
+
// • A globally-unique `id` (used for severity overrides & ignoring)
|
|
8
|
+
// • A descriptive `name` shown in CLI output
|
|
9
|
+
// • A `pattern` regex (with the `g` flag so scanners can find all matches)
|
|
10
|
+
// • An optional `provider` key mapping into the PROVIDER_MAP
|
|
11
|
+
// • A `severity` level
|
|
12
|
+
// • A human-readable `description`
|
|
13
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
14
|
+
export const SECRET_RULES = [
|
|
15
|
+
// ── AWS ──────────────────────────────────────────────────────────────
|
|
16
|
+
{
|
|
17
|
+
id: "aws-access-key",
|
|
18
|
+
name: "AWS Access Key ID",
|
|
19
|
+
pattern: /(?<![A-Z0-9])AKIA[0-9A-Z]{16}(?![A-Z0-9])/g,
|
|
20
|
+
provider: "aws",
|
|
21
|
+
severity: "critical",
|
|
22
|
+
description: "AWS Access Key IDs always start with AKIA followed by 16 alphanumeric characters.",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
id: "aws-secret-key",
|
|
26
|
+
name: "AWS Secret Access Key",
|
|
27
|
+
pattern: /(?<![A-Za-z0-9/+=])[A-Za-z0-9/+]{40}(?![A-Za-z0-9/+=])/g,
|
|
28
|
+
provider: "aws",
|
|
29
|
+
severity: "critical",
|
|
30
|
+
description: "AWS Secret Access Keys are 40-character base64 strings.",
|
|
31
|
+
},
|
|
32
|
+
// ── Stripe ───────────────────────────────────────────────────────────
|
|
33
|
+
{
|
|
34
|
+
id: "stripe-secret-key",
|
|
35
|
+
name: "Stripe Secret Key",
|
|
36
|
+
pattern: /sk_live_[a-zA-Z0-9]{24,}/g,
|
|
37
|
+
provider: "stripe",
|
|
38
|
+
severity: "critical",
|
|
39
|
+
description: "Stripe live secret key — grants full API access.",
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "stripe-test-secret-key",
|
|
43
|
+
name: "Stripe Test Secret Key",
|
|
44
|
+
pattern: /sk_test_[a-zA-Z0-9]{24,}/g,
|
|
45
|
+
provider: "stripe",
|
|
46
|
+
severity: "warning",
|
|
47
|
+
description: "Stripe test secret key — should still not be committed.",
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: "stripe-publishable-key",
|
|
51
|
+
name: "Stripe Publishable Key",
|
|
52
|
+
pattern: /pk_(live|test)_[a-zA-Z0-9]{24,}/g,
|
|
53
|
+
provider: "stripe",
|
|
54
|
+
severity: "info",
|
|
55
|
+
description: "Stripe publishable key — safe for client bundles but tracked for awareness.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: "stripe-restricted-key",
|
|
59
|
+
name: "Stripe Restricted Key",
|
|
60
|
+
pattern: /rk_(live|test)_[a-zA-Z0-9]{24,}/g,
|
|
61
|
+
provider: "stripe",
|
|
62
|
+
severity: "critical",
|
|
63
|
+
description: "Stripe restricted key with custom permissions.",
|
|
64
|
+
},
|
|
65
|
+
// ── OpenAI ───────────────────────────────────────────────────────────
|
|
66
|
+
{
|
|
67
|
+
id: "openai-api-key",
|
|
68
|
+
name: "OpenAI API Key",
|
|
69
|
+
pattern: /sk-[a-zA-Z0-9]{20,}/g,
|
|
70
|
+
provider: "openai",
|
|
71
|
+
severity: "critical",
|
|
72
|
+
description: "OpenAI API key — grants access to GPT and other models.",
|
|
73
|
+
},
|
|
74
|
+
// ── GitHub ───────────────────────────────────────────────────────────
|
|
75
|
+
{
|
|
76
|
+
id: "github-token",
|
|
77
|
+
name: "GitHub Token",
|
|
78
|
+
pattern: /gh[pousr]_[A-Za-z0-9_]{36,}/g,
|
|
79
|
+
provider: "github",
|
|
80
|
+
severity: "critical",
|
|
81
|
+
description: "GitHub personal access token, OAuth token, or app token.",
|
|
82
|
+
},
|
|
83
|
+
// ── Slack ────────────────────────────────────────────────────────────
|
|
84
|
+
{
|
|
85
|
+
id: "slack-token",
|
|
86
|
+
name: "Slack Token",
|
|
87
|
+
pattern: /xox[bps]-[0-9]+-[0-9]+-[a-zA-Z0-9]+/g,
|
|
88
|
+
provider: "slack",
|
|
89
|
+
severity: "critical",
|
|
90
|
+
description: "Slack bot, user, or app token.",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "slack-webhook",
|
|
94
|
+
name: "Slack Webhook URL",
|
|
95
|
+
pattern: /https:\/\/hooks\.slack\.com\/services\/T[A-Z0-9]+\/B[A-Z0-9]+\/[a-zA-Z0-9]+/g,
|
|
96
|
+
provider: "slack",
|
|
97
|
+
severity: "critical",
|
|
98
|
+
description: "Slack incoming webhook URL — can post messages to a channel.",
|
|
99
|
+
},
|
|
100
|
+
// ── Google ───────────────────────────────────────────────────────────
|
|
101
|
+
{
|
|
102
|
+
id: "google-api-key",
|
|
103
|
+
name: "Google API Key",
|
|
104
|
+
pattern: /AIza[0-9A-Za-z\-_]{35}/g,
|
|
105
|
+
provider: "google",
|
|
106
|
+
severity: "critical",
|
|
107
|
+
description: "Google Cloud / Maps / Firebase API key.",
|
|
108
|
+
},
|
|
109
|
+
// ── Twilio ───────────────────────────────────────────────────────────
|
|
110
|
+
{
|
|
111
|
+
id: "twilio-api-key",
|
|
112
|
+
name: "Twilio API Key",
|
|
113
|
+
pattern: /SK[0-9a-fA-F]{32}/g,
|
|
114
|
+
provider: "twilio",
|
|
115
|
+
severity: "critical",
|
|
116
|
+
description: "Twilio API key SID.",
|
|
117
|
+
},
|
|
118
|
+
// ── SendGrid ─────────────────────────────────────────────────────────
|
|
119
|
+
{
|
|
120
|
+
id: "sendgrid-api-key",
|
|
121
|
+
name: "SendGrid API Key",
|
|
122
|
+
pattern: /SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/g,
|
|
123
|
+
provider: "sendgrid",
|
|
124
|
+
severity: "critical",
|
|
125
|
+
description: "SendGrid API key.",
|
|
126
|
+
},
|
|
127
|
+
// ── Supabase ─────────────────────────────────────────────────────────
|
|
128
|
+
{
|
|
129
|
+
id: "supabase-service-key",
|
|
130
|
+
name: "Supabase Service Role Key",
|
|
131
|
+
pattern: /sbp_[a-f0-9]{40}/g,
|
|
132
|
+
provider: "supabase",
|
|
133
|
+
severity: "critical",
|
|
134
|
+
description: "Supabase service-role key — bypasses RLS.",
|
|
135
|
+
},
|
|
136
|
+
// ── Database URLs ────────────────────────────────────────────────────
|
|
137
|
+
{
|
|
138
|
+
id: "database-url",
|
|
139
|
+
name: "Database Connection String",
|
|
140
|
+
pattern: /(postgres|postgresql|mysql|mongodb|mongodb\+srv):\/\/[^\s"'`]+:[^\s"'`]+@[^\s"'`]+/g,
|
|
141
|
+
severity: "critical",
|
|
142
|
+
description: "Database connection string with embedded credentials.",
|
|
143
|
+
},
|
|
144
|
+
// ── JWT ──────────────────────────────────────────────────────────────
|
|
145
|
+
{
|
|
146
|
+
id: "jwt-token",
|
|
147
|
+
name: "JSON Web Token",
|
|
148
|
+
pattern: /eyJ[A-Za-z0-9_-]+\.eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,
|
|
149
|
+
severity: "warning",
|
|
150
|
+
description: "JSON Web Token — may contain sensitive claims.",
|
|
151
|
+
},
|
|
152
|
+
// ── Private Keys ─────────────────────────────────────────────────────
|
|
153
|
+
{
|
|
154
|
+
id: "private-key",
|
|
155
|
+
name: "Private Key",
|
|
156
|
+
pattern: /-----BEGIN (?:RSA |EC |DSA )?PRIVATE KEY-----/g,
|
|
157
|
+
severity: "critical",
|
|
158
|
+
description: "PEM-encoded private key header.",
|
|
159
|
+
},
|
|
160
|
+
// ── Mailgun ──────────────────────────────────────────────────────────
|
|
161
|
+
{
|
|
162
|
+
id: "mailgun-api-key",
|
|
163
|
+
name: "Mailgun API Key",
|
|
164
|
+
pattern: /key-[a-f0-9]{32}/g,
|
|
165
|
+
provider: "mailgun",
|
|
166
|
+
severity: "critical",
|
|
167
|
+
description: "Mailgun API key.",
|
|
168
|
+
},
|
|
169
|
+
// ── Mailchimp ────────────────────────────────────────────────────────
|
|
170
|
+
{
|
|
171
|
+
id: "mailchimp-api-key",
|
|
172
|
+
name: "Mailchimp API Key",
|
|
173
|
+
pattern: /[a-f0-9]{32}-us\d{1,2}/g,
|
|
174
|
+
provider: "mailchimp",
|
|
175
|
+
severity: "critical",
|
|
176
|
+
description: "Mailchimp API key — includes datacenter suffix.",
|
|
177
|
+
},
|
|
178
|
+
// ── Heroku ───────────────────────────────────────────────────────────
|
|
179
|
+
{
|
|
180
|
+
id: "heroku-api-key",
|
|
181
|
+
name: "Heroku API Key",
|
|
182
|
+
pattern: /[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}/g,
|
|
183
|
+
provider: "heroku",
|
|
184
|
+
severity: "warning",
|
|
185
|
+
description: "Heroku API key (UUID format).",
|
|
186
|
+
},
|
|
187
|
+
// ── DigitalOcean ─────────────────────────────────────────────────────
|
|
188
|
+
{
|
|
189
|
+
id: "digitalocean-token",
|
|
190
|
+
name: "DigitalOcean Token",
|
|
191
|
+
pattern: /dop_v1_[a-f0-9]{64}/g,
|
|
192
|
+
provider: "digitalocean",
|
|
193
|
+
severity: "critical",
|
|
194
|
+
description: "DigitalOcean personal access token.",
|
|
195
|
+
},
|
|
196
|
+
// ── Generic high-entropy assignment (catch-all) ──────────────────────
|
|
197
|
+
{
|
|
198
|
+
id: "generic-high-entropy",
|
|
199
|
+
name: "High-Entropy String",
|
|
200
|
+
pattern: /(?:api[_-]?key|api[_-]?secret|auth[_-]?token|access[_-]?token|secret[_-]?key|private[_-]?key|password|passwd|credential)\s*[:=]\s*['"]([A-Za-z0-9/+=_\-.]{16,})['"/]?/gi,
|
|
201
|
+
severity: "warning",
|
|
202
|
+
description: "Assignment of a high-entropy string to a variable with a secret-like name.",
|
|
203
|
+
},
|
|
204
|
+
];
|
|
205
|
+
//# sourceMappingURL=secret-rules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-rules.js","sourceRoot":"","sources":["../../../src/core/rules/secret-rules.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ParsedEnvEntry, ParsedEnvFile, ScanFinding } from "../../types/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse the content of a `.env` file into a structured `ParsedEnvFile`.
|
|
4
|
+
*
|
|
5
|
+
* Handles:
|
|
6
|
+
* • Comments (lines starting with `#`)
|
|
7
|
+
* • Empty / whitespace-only lines
|
|
8
|
+
* • Inline comments (`VAR=value # comment`)
|
|
9
|
+
* • Single-quoted, double-quoted, and backtick-quoted values
|
|
10
|
+
* • Multiline values enclosed in double-quotes (using `\n` or real newlines)
|
|
11
|
+
* • `export` prefix (e.g. `export FOO=bar`)
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseEnvFile(content: string, filePath: string): ParsedEnvFile;
|
|
14
|
+
/**
|
|
15
|
+
* Discover all `.env*` files in a directory tree, following common
|
|
16
|
+
* naming conventions: `.env`, `.env.local`, `.env.development`, etc.
|
|
17
|
+
*
|
|
18
|
+
* Excludes `node_modules`, `.git`, `dist`, and `build` directories.
|
|
19
|
+
*/
|
|
20
|
+
export declare function findEnvFiles(dir: string): Promise<string[]>;
|
|
21
|
+
/**
|
|
22
|
+
* Cross-compare multiple parsed env files and produce findings for
|
|
23
|
+
* variables that exist in one file but are missing from another.
|
|
24
|
+
*
|
|
25
|
+
* Template files (`.env.example`, `.env.template`, `.env.sample`) are
|
|
26
|
+
* treated as the "source of truth" — variables present in a template
|
|
27
|
+
* but missing from an actual env file produce a finding.
|
|
28
|
+
*/
|
|
29
|
+
export declare function diffEnvFiles(filesOrFileA: ParsedEnvFile[] | ParsedEnvFile, fileB?: ParsedEnvFile): ScanFinding[];
|
|
30
|
+
/**
|
|
31
|
+
* Scan source code for references to environment variables.
|
|
32
|
+
* Returns a deduplicated list of variable names found.
|
|
33
|
+
*/
|
|
34
|
+
export declare function scanCodeForEnvRefs(content: string, _filePath?: string): string[] & {
|
|
35
|
+
size: number;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Given the env var names referenced in code and the env vars actually
|
|
39
|
+
* defined, produce findings for any referenced vars that are missing.
|
|
40
|
+
*/
|
|
41
|
+
export declare function findMissingEnvVars(codeRefs: string[] | Set<string>, envVars: string[] | Set<string>, codeFile: string): ScanFinding[];
|
|
42
|
+
/**
|
|
43
|
+
* Given the env var names referenced in code and all env entries,
|
|
44
|
+
* produce findings for env vars that are defined but never used.
|
|
45
|
+
*/
|
|
46
|
+
export declare function findUnusedEnvVars(firstArg: string[] | Set<string>, secondArg: ParsedEnvEntry[] | Set<string>, envFile: string): ScanFinding[];
|
|
47
|
+
//# sourceMappingURL=env.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../../src/core/scan/env.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EACV,cAAc,EACd,aAAa,EACb,WAAW,EACZ,MAAM,sBAAsB,CAAC;AAoD9B;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,aAAa,CAsF7E;AAED;;;;;GAKG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CASjE;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,aAAa,EAAE,GAAG,aAAa,EAC7C,KAAK,CAAC,EAAE,aAAa,GACpB,WAAW,EAAE,CA2Cf;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,MAAM,EAAE,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAgB7B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EAChC,OAAO,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EAC/B,QAAQ,EAAE,MAAM,GACf,WAAW,EAAE,CA8Bf;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EAChC,SAAS,EAAE,cAAc,EAAE,GAAG,GAAG,CAAC,MAAM,CAAC,EACzC,OAAO,EAAE,MAAM,GACd,WAAW,EAAE,CAgDf"}
|