@vaultcompass/vault-guard-core 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 +21 -0
- package/dist/baseline.d.ts +24 -0
- package/dist/baseline.d.ts.map +1 -0
- package/dist/baseline.js +87 -0
- package/dist/baseline.js.map +1 -0
- package/dist/config-validate.d.ts +13 -0
- package/dist/config-validate.d.ts.map +1 -0
- package/dist/config-validate.js +111 -0
- package/dist/config-validate.js.map +1 -0
- package/dist/config.d.ts +69 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +106 -0
- package/dist/config.js.map +1 -0
- package/dist/diagnostics.d.ts +64 -0
- package/dist/diagnostics.d.ts.map +1 -0
- package/dist/diagnostics.js +59 -0
- package/dist/diagnostics.js.map +1 -0
- package/dist/errors.d.ts +63 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +98 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +53 -0
- package/dist/index.js.map +1 -0
- package/dist/match-fingerprint.d.ts +7 -0
- package/dist/match-fingerprint.d.ts.map +1 -0
- package/dist/match-fingerprint.js +28 -0
- package/dist/match-fingerprint.js.map +1 -0
- package/dist/scan-output.d.ts +65 -0
- package/dist/scan-output.d.ts.map +1 -0
- package/dist/scan-output.js +140 -0
- package/dist/scan-output.js.map +1 -0
- package/dist/scanners/index.d.ts +5 -0
- package/dist/scanners/index.d.ts.map +1 -0
- package/dist/scanners/index.js +21 -0
- package/dist/scanners/index.js.map +1 -0
- package/dist/scanners/pre-commit-hook.d.ts +41 -0
- package/dist/scanners/pre-commit-hook.d.ts.map +1 -0
- package/dist/scanners/pre-commit-hook.js +389 -0
- package/dist/scanners/pre-commit-hook.js.map +1 -0
- package/dist/scanners/secret-scanner.d.ts +99 -0
- package/dist/scanners/secret-scanner.d.ts.map +1 -0
- package/dist/scanners/secret-scanner.js +422 -0
- package/dist/scanners/secret-scanner.js.map +1 -0
- package/dist/scanners/token-counter.d.ts +27 -0
- package/dist/scanners/token-counter.d.ts.map +1 -0
- package/dist/scanners/token-counter.js +121 -0
- package/dist/scanners/token-counter.js.map +1 -0
- package/dist/types.d.ts +36 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/entropy.d.ts +17 -0
- package/dist/utils/entropy.d.ts.map +1 -0
- package/dist/utils/entropy.js +35 -0
- package/dist/utils/entropy.js.map +1 -0
- package/dist/utils/file-utils.d.ts +39 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +442 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/git-utils.d.ts +12 -0
- package/dist/utils/git-utils.d.ts.map +1 -0
- package/dist/utils/git-utils.js +55 -0
- package/dist/utils/git-utils.js.map +1 -0
- package/dist/utils/path-severity.d.ts +17 -0
- package/dist/utils/path-severity.d.ts.map +1 -0
- package/dist/utils/path-severity.js +96 -0
- package/dist/utils/path-severity.js.map +1 -0
- package/dist/utils/placeholder.d.ts +53 -0
- package/dist/utils/placeholder.d.ts.map +1 -0
- package/dist/utils/placeholder.js +198 -0
- package/dist/utils/placeholder.js.map +1 -0
- package/dist/utils/regex-safety.d.ts +102 -0
- package/dist/utils/regex-safety.d.ts.map +1 -0
- package/dist/utils/regex-safety.js +193 -0
- package/dist/utils/regex-safety.js.map +1 -0
- package/dist/utils/scan-file.d.ts +29 -0
- package/dist/utils/scan-file.d.ts.map +1 -0
- package/dist/utils/scan-file.js +125 -0
- package/dist/utils/scan-file.js.map +1 -0
- package/package.json +51 -0
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SecretScanner = void 0;
|
|
7
|
+
exports.getBuiltinPatternDocEntries = getBuiltinPatternDocEntries;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const entropy_1 = require("../utils/entropy");
|
|
10
|
+
const placeholder_1 = require("../utils/placeholder");
|
|
11
|
+
const path_severity_1 = require("../utils/path-severity");
|
|
12
|
+
const regex_safety_1 = require("../utils/regex-safety");
|
|
13
|
+
/**
|
|
14
|
+
* Vendor-specific patterns anchored to known prefixes / structures.
|
|
15
|
+
*
|
|
16
|
+
* Deliberately NOT included (too broad / not actual secrets):
|
|
17
|
+
* - cohere (`[a-zA-Z0-9]{40}`) — matches git SHAs, MD5s, …
|
|
18
|
+
* - aws-secret (`[a-zA-Z0-9/+]{40}`) — matches any base-64-ish string
|
|
19
|
+
* - circleci-token (`[a-zA-Z0-9_-]{40}`) — identical problem
|
|
20
|
+
* - jenkins-token (`[a-zA-Z0-9]{32}`) — matches MD5 hashes
|
|
21
|
+
* - kubernetes-token (JWT) — merged into jwt-token
|
|
22
|
+
* - elasticsearch-url (`https://u:p@h:n`) — matches any auth URL
|
|
23
|
+
* - ssh-rsa-public / ssh-ed25519-public — public keys are NOT secrets
|
|
24
|
+
* - google-analytics / google-analytics-4 — publishable measurement IDs
|
|
25
|
+
* - twilio-account (AC…) — public Account SID, not secret
|
|
26
|
+
*
|
|
27
|
+
* AWS secret access key is retained as a context-anchored pattern only.
|
|
28
|
+
*/
|
|
29
|
+
const BUILTIN_PATTERNS = new Map([
|
|
30
|
+
// --- AI / ML providers ---
|
|
31
|
+
['anthropic', { regex: /sk-ant-[a-zA-Z0-9_-]{20,}/g, severity: 'critical' }],
|
|
32
|
+
['openai', { regex: /sk-[a-zA-Z0-9]{48}/g, severity: 'critical' }],
|
|
33
|
+
['openai-project', { regex: /sk-proj-[a-zA-Z0-9_-]{48,}/g, severity: 'critical' }],
|
|
34
|
+
['huggingface', { regex: /hf_[a-zA-Z0-9]{34,}/g, severity: 'critical' }],
|
|
35
|
+
['replicate', { regex: /r8_[a-zA-Z0-9]{32}/g, severity: 'critical' }],
|
|
36
|
+
// --- Payment processors ---
|
|
37
|
+
['stripe', { regex: /sk_live_[a-zA-Z0-9]{24,}/g, severity: 'critical' }],
|
|
38
|
+
['stripe-test', { regex: /sk_test_[a-zA-Z0-9]{24,}/g, severity: 'high' }],
|
|
39
|
+
['paypal', { regex: /access_token\$production\$[a-zA-Z0-9]{20,}/g, severity: 'critical' }],
|
|
40
|
+
// --- Cloud providers ---
|
|
41
|
+
['aws-access', { regex: /AKIA[0-9A-Z]{16}/g, severity: 'critical' }],
|
|
42
|
+
// Context-anchored AWS secret: only flags values that appear on the same
|
|
43
|
+
// line as the canonical env-var / config-key name.
|
|
44
|
+
['aws-secret-context', { regex: /(?:aws_secret_access_key|AWS_SECRET_ACCESS_KEY)\s*[=:]\s*["']?([a-zA-Z0-9/+]{40})/gi, severity: 'critical' }],
|
|
45
|
+
['gcp-service-account', { regex: /"type":\s*"service_account"/g, severity: 'critical' }],
|
|
46
|
+
['gcp-api-key', { regex: /AIza[a-zA-Z0-9_-]{35}/g, severity: 'critical' }],
|
|
47
|
+
['gcp-oauth', { regex: /[0-9]+-[a-zA-Z0-9_]{32}\.apps\.googleusercontent\.com/g, severity: 'critical' }],
|
|
48
|
+
['azure-storage', { regex: /DefaultEndpointsProtocol=https;AccountName=[^;]+;AccountKey=[A-Za-z0-9+/=]{20,}/g, severity: 'critical' }],
|
|
49
|
+
// --- Database connection strings ---
|
|
50
|
+
['postgresql-url', { regex: /postgres(?:ql)?:\/\/[^:@\s]+:[^@\s]+@[^:\s/]+(?::\d+)?\/\S+/g, severity: 'critical', connectionString: true }],
|
|
51
|
+
['mysql-url', { regex: /mysql:\/\/[^:@\s]+:[^@\s]+@[^:\s/]+(?::\d+)?\/\S+/g, severity: 'critical', connectionString: true }],
|
|
52
|
+
['mongodb-url', { regex: /mongodb(?:\+srv)?:\/\/[^:@\s]+:[^@\s]+@[^:\s/]+(?::\d+)?/g, severity: 'critical', connectionString: true }],
|
|
53
|
+
['redis-url', { regex: /rediss?:\/\/[^:@\s]+:[^@\s]+@[^:\s/]+(?::\d+)/g, severity: 'critical', connectionString: true }],
|
|
54
|
+
// --- Source control tokens ---
|
|
55
|
+
['github-token', { regex: /gh[pousor]_[a-zA-Z0-9]{36}/g, severity: 'critical' }],
|
|
56
|
+
['github-pat', { regex: /github_pat_[a-zA-Z0-9_]{82}/g, severity: 'critical' }],
|
|
57
|
+
['gitlab-token', { regex: /glpat-[a-zA-Z0-9_-]{20}/g, severity: 'critical' }],
|
|
58
|
+
['bitbucket-token', { regex: /BBDC-[a-zA-Z0-9_-]{40}/g, severity: 'critical' }],
|
|
59
|
+
// --- Communication platforms ---
|
|
60
|
+
['slack-webhook', { regex: /hooks\.slack\.com\/services\/[A-Z0-9]{9,}\/[A-Z0-9]{9,}\/[a-zA-Z0-9]{20,}/g, severity: 'critical' }],
|
|
61
|
+
['slack-token', { regex: /xox[baprs]-[a-zA-Z0-9-]{10,}/g, severity: 'critical' }],
|
|
62
|
+
['discord-webhook', { regex: /discord\.com\/api\/webhooks\/[0-9]{17,20}\/[a-zA-Z0-9_-]{60,}/g, severity: 'critical' }],
|
|
63
|
+
// --- Email / messaging services ---
|
|
64
|
+
['sendgrid-api', { regex: /SG\.[a-zA-Z0-9_-]{22}\.[a-zA-Z0-9_-]{43}/g, severity: 'critical' }],
|
|
65
|
+
['resend-api', { regex: /re_[a-zA-Z0-9]{32,}/g, severity: 'critical' }],
|
|
66
|
+
['mailgun-api', { regex: /key-[a-zA-Z0-9]{32}/g, severity: 'critical', minEntropy: 3.5 }],
|
|
67
|
+
// --- Package managers ---
|
|
68
|
+
['npm-token', { regex: /npm_[a-zA-Z0-9]{36}/g, severity: 'critical' }],
|
|
69
|
+
// --- Monitoring ---
|
|
70
|
+
['newrelic-api', { regex: /NRAK-[a-zA-Z0-9]{26}/g, severity: 'critical' }],
|
|
71
|
+
// --- E-commerce ---
|
|
72
|
+
['shopify-admin', { regex: /shp(?:ss|at|ca)_[a-zA-Z0-9]{32}/g, severity: 'critical' }],
|
|
73
|
+
// --- Keys and auth tokens ---
|
|
74
|
+
['ssh-private-key', { regex: /-----BEGIN [A-Z ]+ PRIVATE KEY-----/g, severity: 'critical' }],
|
|
75
|
+
['jwt-token', { regex: /eyJ[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+/g, severity: 'high' }],
|
|
76
|
+
// Generic patterns — entropy-gated AND placeholder-filtered (aggressive) to
|
|
77
|
+
// suppress false positives on documentation samples and unit-test fixtures.
|
|
78
|
+
['bearer-token', { regex: /Bearer [a-zA-Z0-9_-]{20,}/g, severity: 'high', minEntropy: 3.5, aggressivePlaceholder: true }],
|
|
79
|
+
['api-key-generic', { regex: /api[_-]?key["']?\s*[:=]\s*["']?([a-zA-Z0-9_-]{20,})/gi, severity: 'high', minEntropy: 3.5, aggressivePlaceholder: true }],
|
|
80
|
+
['secret-generic', { regex: /secret["']?\s*[:=]\s*["']?([a-zA-Z0-9_-]{20,})/gi, severity: 'high', minEntropy: 3.5, aggressivePlaceholder: true }],
|
|
81
|
+
// Negative lookbehind prevents matching when `password` is a suffix of a
|
|
82
|
+
// compound identifier (e.g. `email-reset-password`, `changePassword`).
|
|
83
|
+
// Only standalone assignments trigger — `password =`, `password:`, etc.
|
|
84
|
+
['password-in-code', { regex: /(?<![a-zA-Z0-9_-])password["']?\s*[:=]\s*["']([a-zA-Z0-9_\-!@#$%^&*]{12,})/gi, severity: 'high', minEntropy: 3.2, aggressivePlaceholder: true }],
|
|
85
|
+
]);
|
|
86
|
+
/**
|
|
87
|
+
* Low-precision generic assignment patterns (`<key> = <value>`) whose captured
|
|
88
|
+
* value may be an unquoted code identifier rather than a literal secret. Only
|
|
89
|
+
* these are subject to the function-call suppression heuristic; vendor- and
|
|
90
|
+
* context-anchored detectors are deliberately excluded.
|
|
91
|
+
*/
|
|
92
|
+
const GENERIC_ASSIGNMENT_IDS = new Set(['secret-generic', 'api-key-generic', 'password-in-code']);
|
|
93
|
+
/** Stable insertion order of {@link BUILTIN_PATTERNS}. */
|
|
94
|
+
function getBuiltinPatternDocEntries() {
|
|
95
|
+
return [...BUILTIN_PATTERNS.entries()].map(([id, entry]) => ({
|
|
96
|
+
id,
|
|
97
|
+
severity: entry.severity,
|
|
98
|
+
...(entry.minEntropy !== undefined ? { minEntropy: entry.minEntropy } : {}),
|
|
99
|
+
regexSource: entry.regex.source,
|
|
100
|
+
regexFlags: entry.regex.flags,
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
// ---------------------------------------------------------------------------
|
|
104
|
+
// Severity ranking (higher = worse)
|
|
105
|
+
// ---------------------------------------------------------------------------
|
|
106
|
+
const SEVERITY_RANK = {
|
|
107
|
+
critical: 4,
|
|
108
|
+
high: 3,
|
|
109
|
+
medium: 2,
|
|
110
|
+
low: 1,
|
|
111
|
+
};
|
|
112
|
+
// ---------------------------------------------------------------------------
|
|
113
|
+
// SecretScanner
|
|
114
|
+
// ---------------------------------------------------------------------------
|
|
115
|
+
class SecretScanner {
|
|
116
|
+
patterns;
|
|
117
|
+
entropyThreshold;
|
|
118
|
+
constructor(config) {
|
|
119
|
+
this.entropyThreshold = config?.entropy_threshold ?? entropy_1.DEFAULT_ENTROPY_THRESHOLD;
|
|
120
|
+
// Start from a mutable copy of the built-ins.
|
|
121
|
+
this.patterns = new Map([...BUILTIN_PATTERNS].map(([k, v]) => [k, { ...v, regex: new RegExp(v.regex.source, v.regex.flags) }]));
|
|
122
|
+
// Apply severity overrides / "off" switches.
|
|
123
|
+
if (config?.severity_overrides) {
|
|
124
|
+
for (const [id, override] of Object.entries(config.severity_overrides)) {
|
|
125
|
+
if (override === 'off') {
|
|
126
|
+
this.patterns.delete(id);
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
const entry = this.patterns.get(id);
|
|
130
|
+
if (entry) {
|
|
131
|
+
this.patterns.set(id, { ...entry, severity: override });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
// Compile and append extra patterns from config.
|
|
137
|
+
//
|
|
138
|
+
// Security policy: every user-supplied regex passes through
|
|
139
|
+
// `validateRegexSafety` (heuristic ReDoS check). Patterns that fail are
|
|
140
|
+
// **not** silently skipped — that is exactly the behaviour the audit
|
|
141
|
+
// flagged (Audit §14: silent error swallows). They are reported via
|
|
142
|
+
// `extraPatternRejections` for the caller (CLI / MCP) to surface to the
|
|
143
|
+
// user, then dropped.
|
|
144
|
+
//
|
|
145
|
+
// `extra_patterns_unsafe: true` opts out of the heuristic, but the length
|
|
146
|
+
// cap still runs as a memory-use backstop.
|
|
147
|
+
if (config?.extra_patterns) {
|
|
148
|
+
const unsafe = config.extra_patterns_unsafe === true;
|
|
149
|
+
for (const ep of config.extra_patterns) {
|
|
150
|
+
const lengthCheck = (0, regex_safety_1.validateRegexLength)(ep.regex);
|
|
151
|
+
if (!lengthCheck.ok) {
|
|
152
|
+
this.extraPatternRejections.push({
|
|
153
|
+
id: ep.id,
|
|
154
|
+
reason: lengthCheck.reason ?? 'too_long',
|
|
155
|
+
detail: lengthCheck.detail ?? 'pattern exceeds length cap',
|
|
156
|
+
});
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
if (!unsafe) {
|
|
160
|
+
const safety = (0, regex_safety_1.validateRegexSafety)(ep.regex);
|
|
161
|
+
if (!safety.ok) {
|
|
162
|
+
this.extraPatternRejections.push({
|
|
163
|
+
id: ep.id,
|
|
164
|
+
reason: safety.reason ?? 'invalid_syntax',
|
|
165
|
+
detail: safety.detail ?? 'pattern failed ReDoS safety check',
|
|
166
|
+
});
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
try {
|
|
171
|
+
this.patterns.set(ep.id, {
|
|
172
|
+
regex: new RegExp(ep.regex, 'g'),
|
|
173
|
+
severity: ep.severity,
|
|
174
|
+
...(ep.min_entropy !== undefined ? { minEntropy: ep.min_entropy } : {}),
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
catch (e) {
|
|
178
|
+
this.extraPatternRejections.push({
|
|
179
|
+
id: ep.id,
|
|
180
|
+
reason: 'invalid_syntax',
|
|
181
|
+
detail: e instanceof Error ? e.message : String(e),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Rejected `extra_patterns` from the most recent constructor call.
|
|
189
|
+
*
|
|
190
|
+
* Callers should surface these to the user (stderr today, structured
|
|
191
|
+
* `diagnostics[]` channel post Phase 2.2). A non-empty list means the
|
|
192
|
+
* user's `.vault-guard.json` declared rules that are not active.
|
|
193
|
+
*/
|
|
194
|
+
extraPatternRejections = [];
|
|
195
|
+
/** Number of built-in + extra patterns active after config (severity "off" removes rules). */
|
|
196
|
+
getActivePatternCount() {
|
|
197
|
+
return this.patterns.size;
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Scan a file and return deduplicated, ignore-directive-filtered matches.
|
|
201
|
+
*/
|
|
202
|
+
scan(filePath) {
|
|
203
|
+
if (!fs_1.default.existsSync(filePath))
|
|
204
|
+
return [];
|
|
205
|
+
const content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
206
|
+
// Path-aware severity is applied here (not in scanContent) because it needs
|
|
207
|
+
// the file path. scanContent callers that know the path (scanTextFile*)
|
|
208
|
+
// apply it themselves, so this does not double-apply.
|
|
209
|
+
return (0, path_severity_1.applyPathAwareSeverity)(this.scanContent(content), filePath);
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Scan arbitrary UTF-8 text (editor buffer, pasted snippet, MCP payload).
|
|
213
|
+
* Line numbers and byte offsets are relative to this string.
|
|
214
|
+
*
|
|
215
|
+
* Each call uses fresh `RegExp` instances so overlapping `scanContent` work
|
|
216
|
+
* (e.g. after an `await` in a concurrent worker pool) cannot corrupt
|
|
217
|
+
* `lastIndex` on shared patterns.
|
|
218
|
+
*/
|
|
219
|
+
scanContent(content) {
|
|
220
|
+
const lineIndex = this.buildLineIndex(content);
|
|
221
|
+
const ignoredLines = this.parseIgnoreDirectives(content, lineIndex);
|
|
222
|
+
const raw = [];
|
|
223
|
+
// Fresh `RegExp` per invocation so concurrent or interleaved `scanContent`
|
|
224
|
+
// calls (e.g. across `await` in a worker pool) never share `lastIndex`.
|
|
225
|
+
const patternsForRun = new Map();
|
|
226
|
+
for (const [k, v] of this.patterns) {
|
|
227
|
+
patternsForRun.set(k, {
|
|
228
|
+
...v,
|
|
229
|
+
regex: new RegExp(v.regex.source, v.regex.flags),
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
for (const [type, entry] of patternsForRun) {
|
|
233
|
+
const { regex, severity, minEntropy, aggressivePlaceholder, connectionString } = entry;
|
|
234
|
+
regex.lastIndex = 0;
|
|
235
|
+
let match;
|
|
236
|
+
while ((match = regex.exec(content)) !== null) {
|
|
237
|
+
const rawValue = match[1] ?? match[0];
|
|
238
|
+
const fullMatch = match[0];
|
|
239
|
+
const threshold = minEntropy ?? (minEntropy === 0 ? 0 : undefined);
|
|
240
|
+
if (threshold !== undefined && (0, entropy_1.shannonEntropy)(rawValue) < threshold) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
// Suppress documentation samples / test fixtures (e.g. AWS's
|
|
244
|
+
// `AKIAIOSFODNN7EXAMPLE`, `password: 'testPass1234'`). The aggressive
|
|
245
|
+
// tier only applies to the low-precision generic patterns.
|
|
246
|
+
if ((0, placeholder_1.isPlaceholderSecret)(rawValue, { aggressive: aggressivePlaceholder === true })) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
// Suppress local/dev/example/placeholder connection strings — the
|
|
250
|
+
// dominant FP source on real repos (docker-compose, `.env.example`,
|
|
251
|
+
// test fixtures all carry `postgres://user:pass@localhost/db`).
|
|
252
|
+
if (connectionString === true && (0, placeholder_1.isNonSecretConnectionString)(fullMatch)) {
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
// Suppress the ubiquitous jwt.io sample token (John Doe / sub 1234567890)
|
|
256
|
+
// that appears in API docs and tutorials everywhere.
|
|
257
|
+
if (type === 'jwt-token' && (0, placeholder_1.isSampleJwt)(fullMatch)) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
// Suppress unquoted assignments whose "value" is actually a function
|
|
261
|
+
// call — e.g. `csrf_secret = _add_new_csrf_cookie(request)`. The value
|
|
262
|
+
// capture group stops at `(`, so a `(` immediately following the match
|
|
263
|
+
// means we captured a callee identifier, not a literal secret. Scoped to
|
|
264
|
+
// the low-precision generic assignment patterns only — vendor-anchored
|
|
265
|
+
// and context-anchored detectors (incl. critical `aws-secret-context`)
|
|
266
|
+
// are never weakened by this heuristic.
|
|
267
|
+
if (GENERIC_ASSIGNMENT_IDS.has(type) &&
|
|
268
|
+
content[match.index + fullMatch.length] === '(') {
|
|
269
|
+
continue;
|
|
270
|
+
}
|
|
271
|
+
const line = this.lineFromIndex(lineIndex, match.index);
|
|
272
|
+
if (ignoredLines.has(line))
|
|
273
|
+
continue;
|
|
274
|
+
raw.push({
|
|
275
|
+
type,
|
|
276
|
+
value: this.maskValue(fullMatch),
|
|
277
|
+
line,
|
|
278
|
+
column: match.index,
|
|
279
|
+
matchLength: fullMatch.length,
|
|
280
|
+
severity,
|
|
281
|
+
});
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return this.deduplicateMatches(raw);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Merge matches produced from chunked reads (e.g. line-by-line streaming)
|
|
288
|
+
* using the same overlap / severity rules as a full-file scan.
|
|
289
|
+
*/
|
|
290
|
+
mergeChunkedMatches(matches) {
|
|
291
|
+
return this.deduplicateMatches(matches);
|
|
292
|
+
}
|
|
293
|
+
// ---------------------------------------------------------------------------
|
|
294
|
+
// Private helpers
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
/**
|
|
297
|
+
* Build an index of line-start byte offsets for O(log n) line lookup.
|
|
298
|
+
* Index position 0 = start of line 1.
|
|
299
|
+
*/
|
|
300
|
+
buildLineIndex(content) {
|
|
301
|
+
const idx = [0];
|
|
302
|
+
for (let i = 0; i < content.length; i++) {
|
|
303
|
+
if (content[i] === '\n')
|
|
304
|
+
idx.push(i + 1);
|
|
305
|
+
}
|
|
306
|
+
return idx;
|
|
307
|
+
}
|
|
308
|
+
/** Binary-search the line index to return a 1-based line number. */
|
|
309
|
+
lineFromIndex(lineIndex, byteOffset) {
|
|
310
|
+
let lo = 0;
|
|
311
|
+
let hi = lineIndex.length - 1;
|
|
312
|
+
while (lo <= hi) {
|
|
313
|
+
const mid = (lo + hi) >>> 1;
|
|
314
|
+
if (lineIndex[mid] <= byteOffset)
|
|
315
|
+
lo = mid + 1;
|
|
316
|
+
else
|
|
317
|
+
hi = mid - 1;
|
|
318
|
+
}
|
|
319
|
+
return lo; // 1-based
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Parse inline ignore directives from file content.
|
|
323
|
+
*
|
|
324
|
+
* Supported forms (case-insensitive):
|
|
325
|
+
* `// vault-guard: ignore-line` — ignores that line
|
|
326
|
+
* `// vault-guard: ignore-next-line` — ignores the following line
|
|
327
|
+
* `# vault-guard: ignore-line` — same, for shell/Python/YAML
|
|
328
|
+
* `# vault-guard: ignore-next-line`
|
|
329
|
+
*
|
|
330
|
+
* Returns a Set of 1-based line numbers to ignore.
|
|
331
|
+
*/
|
|
332
|
+
parseIgnoreDirectives(content, lineIndex) {
|
|
333
|
+
const ignored = new Set();
|
|
334
|
+
const lines = content.split('\n');
|
|
335
|
+
for (let i = 0; i < lines.length; i++) {
|
|
336
|
+
const lineNum = i + 1; // 1-based
|
|
337
|
+
const lower = lines[i].toLowerCase();
|
|
338
|
+
if (lower.includes('vault-guard: ignore-line') || lower.includes('vault-guard:ignore-line')) {
|
|
339
|
+
ignored.add(lineNum);
|
|
340
|
+
}
|
|
341
|
+
if (lower.includes('vault-guard: ignore-next-line') || lower.includes('vault-guard:ignore-next-line')) {
|
|
342
|
+
ignored.add(lineNum + 1);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
// lineIndex is available for future column-level ignore; unused here.
|
|
346
|
+
void lineIndex;
|
|
347
|
+
return ignored;
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* Deduplicate matches by overlapping byte ranges.
|
|
351
|
+
*
|
|
352
|
+
* When two matches cover the same (or overlapping) bytes in the file the
|
|
353
|
+
* more-specific (higher-severity or shorter) match is kept. This prevents
|
|
354
|
+
* the same secret from being reported multiple times when several patterns
|
|
355
|
+
* overlap.
|
|
356
|
+
*/
|
|
357
|
+
deduplicateMatches(matches) {
|
|
358
|
+
if (matches.length <= 1)
|
|
359
|
+
return matches;
|
|
360
|
+
// Sort by start offset so we can do a linear sweep.
|
|
361
|
+
const sorted = [...matches].sort((a, b) => a.column - b.column || a.line - b.line);
|
|
362
|
+
const kept = [];
|
|
363
|
+
for (const candidate of sorted) {
|
|
364
|
+
const cStart = candidate.column;
|
|
365
|
+
const cEnd = cStart + candidate.matchLength;
|
|
366
|
+
let dominated = false;
|
|
367
|
+
for (let i = kept.length - 1; i >= 0; i--) {
|
|
368
|
+
const existing = kept[i];
|
|
369
|
+
const eStart = existing.column;
|
|
370
|
+
const eEnd = eStart + existing.matchLength;
|
|
371
|
+
// No possible overlap once we've passed the candidate start by more
|
|
372
|
+
// than the max pattern length (optimisation — safe upper bound: 512).
|
|
373
|
+
if (eEnd < cStart - 512)
|
|
374
|
+
break;
|
|
375
|
+
const overlaps = cStart < eEnd && eStart < cEnd;
|
|
376
|
+
if (!overlaps)
|
|
377
|
+
continue;
|
|
378
|
+
const existingRank = SEVERITY_RANK[existing.severity];
|
|
379
|
+
const candidateRank = SEVERITY_RANK[candidate.severity];
|
|
380
|
+
if (candidateRank > existingRank) {
|
|
381
|
+
// Candidate is more severe — replace existing.
|
|
382
|
+
kept.splice(i, 1);
|
|
383
|
+
}
|
|
384
|
+
else {
|
|
385
|
+
// Existing is at least as severe — drop candidate.
|
|
386
|
+
dominated = true;
|
|
387
|
+
break;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
if (!dominated)
|
|
391
|
+
kept.push(candidate);
|
|
392
|
+
}
|
|
393
|
+
return kept;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Redact a matched secret to a low-information identifier.
|
|
397
|
+
*
|
|
398
|
+
* Format: `<prefix>…(<length>c)` — e.g. `sk-a…(37c)`.
|
|
399
|
+
*
|
|
400
|
+
* Why not show more characters?
|
|
401
|
+
* - 4-char prefix is enough to identify vendor (sk-a, sk_l, ghp_, AKIA, …)
|
|
402
|
+
* without leaking meaningful entropy of the underlying secret.
|
|
403
|
+
* - The exact location is already in `line` / `column`, so users don't
|
|
404
|
+
* need a longer fragment to find the match in source.
|
|
405
|
+
* - Output of this tool is routinely pasted into PRs, Slack, terminals,
|
|
406
|
+
* SARIF uploads, and GitHub Code Scanning — the surface area for
|
|
407
|
+
* leakage is large, so we keep the redaction conservative.
|
|
408
|
+
*
|
|
409
|
+
* For values shorter than 6 chars (rare; broad patterns enforce ≥20)
|
|
410
|
+
* we redact entirely to `*…(<length>c)`.
|
|
411
|
+
*/
|
|
412
|
+
maskValue(value) {
|
|
413
|
+
const PREFIX = 4;
|
|
414
|
+
const lengthTag = `(${value.length}c)`;
|
|
415
|
+
if (value.length < 6) {
|
|
416
|
+
return `*…${lengthTag}`;
|
|
417
|
+
}
|
|
418
|
+
return `${value.substring(0, PREFIX)}…${lengthTag}`;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
exports.SecretScanner = SecretScanner;
|
|
422
|
+
//# sourceMappingURL=secret-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"secret-scanner.js","sourceRoot":"","sources":["../../src/scanners/secret-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { TokenReport } from '../types';
|
|
2
|
+
export declare class TokenCounter {
|
|
3
|
+
private tokenRates;
|
|
4
|
+
/**
|
|
5
|
+
* Count tokens in a file (rough estimation)
|
|
6
|
+
* Real implementation would use tiktoken or similar
|
|
7
|
+
*/
|
|
8
|
+
countTokensInFile(filePath: string): number;
|
|
9
|
+
/**
|
|
10
|
+
* Estimate token count from text with improved accuracy
|
|
11
|
+
* Accounts for code density, symbols, and whitespace
|
|
12
|
+
*/
|
|
13
|
+
estimateTokens(text: string): number;
|
|
14
|
+
/**
|
|
15
|
+
* Calculate cost from token usage
|
|
16
|
+
*/
|
|
17
|
+
calculateCost(provider: 'anthropic' | 'openai', inputTokens: number, outputTokens: number): number;
|
|
18
|
+
/**
|
|
19
|
+
* Generate token report for a directory
|
|
20
|
+
*/
|
|
21
|
+
generateReport(directoryPath: string): TokenReport;
|
|
22
|
+
private getAllFiles;
|
|
23
|
+
private shouldIgnore;
|
|
24
|
+
private shouldIgnoreFile;
|
|
25
|
+
private getExtension;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=token-counter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-counter.d.ts","sourceRoot":"","sources":["../../src/scanners/token-counter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAEvC,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAShB;IAEF;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAS3C;;;OAGG;IACH,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;IA+BpC;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,MAAM;IAOlG;;OAEG;IACH,cAAc,CAAC,aAAa,EAAE,MAAM,GAAG,WAAW;IAyBlD,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,YAAY;IAIpB,OAAO,CAAC,gBAAgB;IAKxB,OAAO,CAAC,YAAY;CAIrB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.TokenCounter = void 0;
|
|
7
|
+
const fs_1 = __importDefault(require("fs"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
class TokenCounter {
|
|
10
|
+
tokenRates = {
|
|
11
|
+
anthropic: {
|
|
12
|
+
input: 3.0, // $3 per million tokens
|
|
13
|
+
output: 15.0 // $15 per million tokens
|
|
14
|
+
},
|
|
15
|
+
openai: {
|
|
16
|
+
input: 5.0,
|
|
17
|
+
output: 15.0
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Count tokens in a file (rough estimation)
|
|
22
|
+
* Real implementation would use tiktoken or similar
|
|
23
|
+
*/
|
|
24
|
+
countTokensInFile(filePath) {
|
|
25
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
26
|
+
return 0;
|
|
27
|
+
}
|
|
28
|
+
const content = fs_1.default.readFileSync(filePath, 'utf-8');
|
|
29
|
+
return this.estimateTokens(content);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Estimate token count from text with improved accuracy
|
|
33
|
+
* Accounts for code density, symbols, and whitespace
|
|
34
|
+
*/
|
|
35
|
+
estimateTokens(text) {
|
|
36
|
+
if (!text || text.length === 0) {
|
|
37
|
+
return 0;
|
|
38
|
+
}
|
|
39
|
+
// Count whitespace-separated words
|
|
40
|
+
const words = text.split(/\s+/).filter(w => w.length > 0);
|
|
41
|
+
const wordCount = words.length;
|
|
42
|
+
// Count symbols and operators (more common in code)
|
|
43
|
+
const symbolMatches = text.match(/[{}[\]();,:.<>+\-*/%=|^&!~?]/g);
|
|
44
|
+
const symbolCount = symbolMatches ? symbolMatches.length : 0;
|
|
45
|
+
// Base estimate: words + symbols (rough approximation)
|
|
46
|
+
let tokenEstimate = wordCount + symbolCount;
|
|
47
|
+
// Adjust for code density (code typically has higher token/word ratio)
|
|
48
|
+
// If text has many symbols relative to words, it's likely code
|
|
49
|
+
const symbolToWordRatio = wordCount > 0 ? symbolCount / wordCount : 0;
|
|
50
|
+
if (symbolToWordRatio > 0.5) {
|
|
51
|
+
// Code-like content: increase estimate
|
|
52
|
+
tokenEstimate = Math.floor(tokenEstimate * 1.3);
|
|
53
|
+
}
|
|
54
|
+
else if (symbolToWordRatio < 0.1) {
|
|
55
|
+
// Natural language: decrease slightly (words are better tokens)
|
|
56
|
+
tokenEstimate = Math.floor(tokenEstimate * 0.9);
|
|
57
|
+
}
|
|
58
|
+
// Ensure minimum estimate
|
|
59
|
+
return Math.max(tokenEstimate, Math.ceil(text.length / 8));
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Calculate cost from token usage
|
|
63
|
+
*/
|
|
64
|
+
calculateCost(provider, inputTokens, outputTokens) {
|
|
65
|
+
const rates = this.tokenRates[provider];
|
|
66
|
+
const inputCost = (inputTokens / 1_000_000) * rates.input;
|
|
67
|
+
const outputCost = (outputTokens / 1_000_000) * rates.output;
|
|
68
|
+
return inputCost + outputCost;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Generate token report for a directory
|
|
72
|
+
*/
|
|
73
|
+
generateReport(directoryPath) {
|
|
74
|
+
let totalTokens = 0;
|
|
75
|
+
const breakdown = {};
|
|
76
|
+
const files = this.getAllFiles(directoryPath);
|
|
77
|
+
for (const file of files) {
|
|
78
|
+
const tokens = this.countTokensInFile(file);
|
|
79
|
+
if (tokens > 0) {
|
|
80
|
+
const ext = this.getExtension(file);
|
|
81
|
+
breakdown[ext] = (breakdown[ext] || 0) + tokens;
|
|
82
|
+
totalTokens += tokens;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Estimate cost (assuming Anthropic)
|
|
86
|
+
const estimatedCost = (totalTokens / 1_000_000) * 3.0;
|
|
87
|
+
return {
|
|
88
|
+
totalTokens,
|
|
89
|
+
estimatedCost,
|
|
90
|
+
breakdown
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
getAllFiles(dirPath) {
|
|
94
|
+
const files = [];
|
|
95
|
+
const items = fs_1.default.readdirSync(dirPath);
|
|
96
|
+
for (const item of items) {
|
|
97
|
+
const fullPath = path_1.default.join(dirPath, item);
|
|
98
|
+
const stat = fs_1.default.statSync(fullPath);
|
|
99
|
+
if (stat.isDirectory() && !this.shouldIgnore(item)) {
|
|
100
|
+
files.push(...this.getAllFiles(fullPath));
|
|
101
|
+
}
|
|
102
|
+
else if (stat.isFile() && !this.shouldIgnoreFile(fullPath)) {
|
|
103
|
+
files.push(fullPath);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return files;
|
|
107
|
+
}
|
|
108
|
+
shouldIgnore(name) {
|
|
109
|
+
return ['node_modules', '.git', 'dist', 'build', 'coverage', '.next'].includes(name);
|
|
110
|
+
}
|
|
111
|
+
shouldIgnoreFile(filePath) {
|
|
112
|
+
const ext = this.getExtension(filePath);
|
|
113
|
+
return ['.png', '.jpg', '.jpeg', '.gif', '.pdf', '.zip', '.lock', '.log'].includes(ext);
|
|
114
|
+
}
|
|
115
|
+
getExtension(filePath) {
|
|
116
|
+
const parts = filePath.split('.');
|
|
117
|
+
return parts.length > 1 ? `.${parts[parts.length - 1]}` : '(no ext)';
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
exports.TokenCounter = TokenCounter;
|
|
121
|
+
//# sourceMappingURL=token-counter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-counter.js","sourceRoot":"","sources":["../../src/scanners/token-counter.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface SecretMatch {
|
|
2
|
+
/** Pattern id (e.g. "anthropic", "aws-access"). */
|
|
3
|
+
type: string;
|
|
4
|
+
/** Masked representation of the matched value (safe to log). */
|
|
5
|
+
value: string;
|
|
6
|
+
/** 1-based line number in the file. */
|
|
7
|
+
line: number;
|
|
8
|
+
/** 0-based absolute byte offset in the file (used for deduplication). */
|
|
9
|
+
column: number;
|
|
10
|
+
/** Byte length of the original match (used for SARIF region output). */
|
|
11
|
+
matchLength: number;
|
|
12
|
+
severity: 'critical' | 'high' | 'medium' | 'low';
|
|
13
|
+
}
|
|
14
|
+
export interface TokenReport {
|
|
15
|
+
totalTokens: number;
|
|
16
|
+
estimatedCost: number;
|
|
17
|
+
breakdown: Record<string, number>;
|
|
18
|
+
}
|
|
19
|
+
export interface GuardStatus {
|
|
20
|
+
security: {
|
|
21
|
+
clean: boolean;
|
|
22
|
+
critical: number;
|
|
23
|
+
warning: number;
|
|
24
|
+
};
|
|
25
|
+
tokens: {
|
|
26
|
+
used: number;
|
|
27
|
+
limit: number;
|
|
28
|
+
cost: number;
|
|
29
|
+
};
|
|
30
|
+
savings: {
|
|
31
|
+
percentage: number;
|
|
32
|
+
amount: number;
|
|
33
|
+
};
|
|
34
|
+
aiActive: boolean;
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,IAAI,EAAE,MAAM,CAAC;IACb,gEAAgE;IAChE,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAC;IACb,yEAAyE;IACzE,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;CAClD;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE;QACR,KAAK,EAAE,OAAO,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;IACF,MAAM,EAAE;QACN,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,OAAO,EAAE;QACP,UAAU,EAAE,MAAM,CAAC;QACnB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,QAAQ,EAAE,OAAO,CAAC;CACnB"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|