@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.
Files changed (82) hide show
  1. package/LICENSE +21 -0
  2. package/dist/baseline.d.ts +24 -0
  3. package/dist/baseline.d.ts.map +1 -0
  4. package/dist/baseline.js +87 -0
  5. package/dist/baseline.js.map +1 -0
  6. package/dist/config-validate.d.ts +13 -0
  7. package/dist/config-validate.d.ts.map +1 -0
  8. package/dist/config-validate.js +111 -0
  9. package/dist/config-validate.js.map +1 -0
  10. package/dist/config.d.ts +69 -0
  11. package/dist/config.d.ts.map +1 -0
  12. package/dist/config.js +106 -0
  13. package/dist/config.js.map +1 -0
  14. package/dist/diagnostics.d.ts +64 -0
  15. package/dist/diagnostics.d.ts.map +1 -0
  16. package/dist/diagnostics.js +59 -0
  17. package/dist/diagnostics.js.map +1 -0
  18. package/dist/errors.d.ts +63 -0
  19. package/dist/errors.d.ts.map +1 -0
  20. package/dist/errors.js +98 -0
  21. package/dist/errors.js.map +1 -0
  22. package/dist/index.d.ts +17 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +53 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/match-fingerprint.d.ts +7 -0
  27. package/dist/match-fingerprint.d.ts.map +1 -0
  28. package/dist/match-fingerprint.js +28 -0
  29. package/dist/match-fingerprint.js.map +1 -0
  30. package/dist/scan-output.d.ts +65 -0
  31. package/dist/scan-output.d.ts.map +1 -0
  32. package/dist/scan-output.js +140 -0
  33. package/dist/scan-output.js.map +1 -0
  34. package/dist/scanners/index.d.ts +5 -0
  35. package/dist/scanners/index.d.ts.map +1 -0
  36. package/dist/scanners/index.js +21 -0
  37. package/dist/scanners/index.js.map +1 -0
  38. package/dist/scanners/pre-commit-hook.d.ts +41 -0
  39. package/dist/scanners/pre-commit-hook.d.ts.map +1 -0
  40. package/dist/scanners/pre-commit-hook.js +389 -0
  41. package/dist/scanners/pre-commit-hook.js.map +1 -0
  42. package/dist/scanners/secret-scanner.d.ts +99 -0
  43. package/dist/scanners/secret-scanner.d.ts.map +1 -0
  44. package/dist/scanners/secret-scanner.js +422 -0
  45. package/dist/scanners/secret-scanner.js.map +1 -0
  46. package/dist/scanners/token-counter.d.ts +27 -0
  47. package/dist/scanners/token-counter.d.ts.map +1 -0
  48. package/dist/scanners/token-counter.js +121 -0
  49. package/dist/scanners/token-counter.js.map +1 -0
  50. package/dist/types.d.ts +36 -0
  51. package/dist/types.d.ts.map +1 -0
  52. package/dist/types.js +3 -0
  53. package/dist/types.js.map +1 -0
  54. package/dist/utils/entropy.d.ts +17 -0
  55. package/dist/utils/entropy.d.ts.map +1 -0
  56. package/dist/utils/entropy.js +35 -0
  57. package/dist/utils/entropy.js.map +1 -0
  58. package/dist/utils/file-utils.d.ts +39 -0
  59. package/dist/utils/file-utils.d.ts.map +1 -0
  60. package/dist/utils/file-utils.js +442 -0
  61. package/dist/utils/file-utils.js.map +1 -0
  62. package/dist/utils/git-utils.d.ts +12 -0
  63. package/dist/utils/git-utils.d.ts.map +1 -0
  64. package/dist/utils/git-utils.js +55 -0
  65. package/dist/utils/git-utils.js.map +1 -0
  66. package/dist/utils/path-severity.d.ts +17 -0
  67. package/dist/utils/path-severity.d.ts.map +1 -0
  68. package/dist/utils/path-severity.js +96 -0
  69. package/dist/utils/path-severity.js.map +1 -0
  70. package/dist/utils/placeholder.d.ts +53 -0
  71. package/dist/utils/placeholder.d.ts.map +1 -0
  72. package/dist/utils/placeholder.js +198 -0
  73. package/dist/utils/placeholder.js.map +1 -0
  74. package/dist/utils/regex-safety.d.ts +102 -0
  75. package/dist/utils/regex-safety.d.ts.map +1 -0
  76. package/dist/utils/regex-safety.js +193 -0
  77. package/dist/utils/regex-safety.js.map +1 -0
  78. package/dist/utils/scan-file.d.ts +29 -0
  79. package/dist/utils/scan-file.d.ts.map +1 -0
  80. package/dist/utils/scan-file.js +125 -0
  81. package/dist/utils/scan-file.js.map +1 -0
  82. package/package.json +51 -0
@@ -0,0 +1,96 @@
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.isTestFilePath = isTestFilePath;
7
+ exports.applyPathAwareSeverity = applyPathAwareSeverity;
8
+ const path_1 = __importDefault(require("path"));
9
+ /**
10
+ * Pattern IDs whose severity is downgraded to `low` in obvious test / fixture
11
+ * paths. Two groups:
12
+ *
13
+ * - Low-precision generic patterns (`password-in-code`, …) — common in test
14
+ * scaffolding and rarely real leaks there.
15
+ * - Connection strings and key/token shapes (`postgresql-url`,
16
+ * `ssh-private-key`, `jwt-token`, …) — test suites are full of throwaway
17
+ * DSNs, fixture PEMs, and sample tokens. Downgrading (not suppressing)
18
+ * keeps them visible at `low` without drowning real criticals.
19
+ *
20
+ * Hard vendor-anchored API-key patterns (anthropic, aws-access, stripe,
21
+ * github-token, …) are intentionally **absent**: a real provider key is a real
22
+ * key even in a test file, and those patterns have near-zero false positives.
23
+ */
24
+ const TEST_PATH_DOWNGRADE_IDS = new Set([
25
+ // generic / assignment
26
+ 'password-in-code',
27
+ 'api-key-generic',
28
+ 'secret-generic',
29
+ 'bearer-token',
30
+ // connection strings
31
+ 'postgresql-url',
32
+ 'mysql-url',
33
+ 'mongodb-url',
34
+ 'redis-url',
35
+ // key / token shapes
36
+ 'ssh-private-key',
37
+ 'jwt-token',
38
+ ]);
39
+ /**
40
+ * Segments that indicate a file lives in a test / fixture tree.
41
+ * Matched against every directory component in the file path.
42
+ */
43
+ const TEST_DIR_SEGMENTS = new Set([
44
+ '__tests__',
45
+ '__mocks__',
46
+ 'tests',
47
+ 'test',
48
+ 'fixtures',
49
+ 'testdata',
50
+ 'spec',
51
+ 'e2e',
52
+ ]);
53
+ /**
54
+ * File name suffixes / extensions that mark test or fixture files.
55
+ * Checked against `path.basename(filePath)`.
56
+ */
57
+ const TEST_FILE_PATTERNS = [
58
+ /\.test\.[jt]sx?$/,
59
+ /\.spec\.[jt]sx?$/,
60
+ /\.test\.api\.[jt]sx?$/,
61
+ /\.fixture\.[jt]sx?$/,
62
+ ];
63
+ /**
64
+ * Return `true` when `filePath` looks like a test or fixture file.
65
+ */
66
+ function isTestFilePath(filePath) {
67
+ const parts = filePath.split(path_1.default.sep).flatMap(p => p.split('/'));
68
+ if (parts.some(seg => TEST_DIR_SEGMENTS.has(seg)))
69
+ return true;
70
+ const basename = path_1.default.basename(filePath);
71
+ return TEST_FILE_PATTERNS.some(re => re.test(basename));
72
+ }
73
+ /**
74
+ * Downgrade low-precision generic pattern findings to `'low'` severity when
75
+ * they appear inside a test / fixture file.
76
+ *
77
+ * Rationale: password assignments, bearer tokens, and generic api-key patterns
78
+ * are common in test scaffolding (`const password = 'Admin1234!'`) and are
79
+ * rarely real leaked credentials in that context. Vendor-anchored patterns
80
+ * (aws-access, anthropic, stripe, …) are unaffected — a real key in a test
81
+ * file is still worth a `critical` alert.
82
+ */
83
+ function applyPathAwareSeverity(matches, filePath) {
84
+ if (matches.length === 0)
85
+ return matches;
86
+ if (!isTestFilePath(filePath))
87
+ return matches;
88
+ return matches.map(m => {
89
+ if (!TEST_PATH_DOWNGRADE_IDS.has(m.type))
90
+ return m;
91
+ if (m.severity === 'low')
92
+ return m;
93
+ return { ...m, severity: 'low' };
94
+ });
95
+ }
96
+ //# sourceMappingURL=path-severity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"path-severity.js","sourceRoot":"","sources":["../../src/utils/path-severity.ts"],"names":[],"mappings":";;;;;AA+DA,wCAKC;AAYD,wDAYC;AA5FD,gDAAwB;AAGxB;;;;;;;;;;;;;;GAcG;AACH,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC;IACtC,uBAAuB;IACvB,kBAAkB;IAClB,iBAAiB;IACjB,gBAAgB;IAChB,cAAc;IACd,qBAAqB;IACrB,gBAAgB;IAChB,WAAW;IACX,aAAa;IACb,WAAW;IACX,qBAAqB;IACrB,iBAAiB;IACjB,WAAW;CACZ,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IAChC,WAAW;IACX,WAAW;IACX,OAAO;IACP,MAAM;IACN,UAAU;IACV,UAAU;IACV,MAAM;IACN,KAAK;CACN,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,kBAAkB,GAAG;IACzB,kBAAkB;IAClB,kBAAkB;IAClB,uBAAuB;IACvB,qBAAqB;CACtB,CAAC;AAEF;;GAEG;AACH,SAAgB,cAAc,CAAC,QAAgB;IAC7C,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,cAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAClE,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC/D,MAAM,QAAQ,GAAG,cAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACzC,OAAO,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,sBAAsB,CACpC,OAAsB,EACtB,QAAgB;IAEhB,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACzC,IAAI,CAAC,cAAc,CAAC,QAAQ,CAAC;QAAE,OAAO,OAAO,CAAC;IAE9C,OAAO,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE;QACrB,IAAI,CAAC,uBAAuB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC;QACnD,IAAI,CAAC,CAAC,QAAQ,KAAK,KAAK;YAAE,OAAO,CAAC,CAAC;QACnC,OAAO,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,KAAc,EAAE,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Recognise obviously non-secret placeholder / example / test values so that
3
+ * broad patterns stop firing on documentation samples and unit-test fixtures —
4
+ * empirically the dominant real-world false-positive source (e.g. AWS's own
5
+ * documented `AKIAIOSFODNN7EXAMPLE` key, or `const password = 'testPass1234'`).
6
+ *
7
+ * Two tiers, by precision cost:
8
+ *
9
+ * - `standard` (safe for every pattern, including vendor-anchored keys):
10
+ * unambiguous markers that effectively never occur inside a real generated
11
+ * credential — `EXAMPLE`, `changeme`, `your_token_here`, all-`x` padding, …
12
+ *
13
+ * - `aggressive` (opt-in, used only by the low-precision generic / password
14
+ * assignment patterns): additionally treats common test-fixture words
15
+ * (`test`, `sample`, `password`, …) as placeholders. Scoped to those
16
+ * patterns so vendor-anchored keys keep full recall.
17
+ *
18
+ * Matching is substring-based on the lower-cased value. Markers are chosen to
19
+ * be long/specific enough that a real high-entropy secret will not contain them
20
+ * by chance.
21
+ */
22
+ /**
23
+ * Return `true` when a database/Redis connection string is **not** a real
24
+ * credential leak — i.e. it targets a local/dev/docker/example host, or uses
25
+ * obvious placeholder/default credentials.
26
+ *
27
+ * The exploitable secret in a DSN is the password against a *reachable* host.
28
+ * We suppress when either:
29
+ * 1. the host is local, a bare docker-compose service name, or a reserved
30
+ * TLD (`localhost`, `mysql`, `db.local`, …) — not remotely reachable; or
31
+ * 2. the password is a placeholder/default (`pass`, `PASSWORD`, `root:root`,
32
+ * `${DB_PASS}`, `<your-password>`, …).
33
+ *
34
+ * A real remote host with a real password (e.g.
35
+ * `postgres://app:8Fk2$mQ9z@db.prod.example-corp.com/main`) is **not**
36
+ * suppressed.
37
+ */
38
+ /**
39
+ * Recognise the canonical jwt.io / RFC 7519 sample token that is pasted into
40
+ * countless READMEs, OpenAPI specs, and tutorials. Its decoded payload carries
41
+ * the well-known sample claims (`sub: "1234567890"`, `name: "John Doe"`,
42
+ * `iat: 1516239022`). These are never real credentials.
43
+ */
44
+ export declare function isSampleJwt(token: string): boolean;
45
+ export declare function isNonSecretConnectionString(url: string): boolean;
46
+ /**
47
+ * @returns `true` when `value` looks like a placeholder / example / test
48
+ * credential and should be suppressed.
49
+ */
50
+ export declare function isPlaceholderSecret(value: string, opts?: {
51
+ aggressive?: boolean;
52
+ }): boolean;
53
+ //# sourceMappingURL=placeholder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeholder.d.ts","sourceRoot":"","sources":["../../src/utils/placeholder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AA0FH;;;;;;;;;;;;;;;GAeG;AACH;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAclD;AAED,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAwBhE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,MAAM,EACb,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,OAAO,CAAA;CAAO,GAClC,OAAO,CAiBT"}
@@ -0,0 +1,198 @@
1
+ "use strict";
2
+ /**
3
+ * Recognise obviously non-secret placeholder / example / test values so that
4
+ * broad patterns stop firing on documentation samples and unit-test fixtures —
5
+ * empirically the dominant real-world false-positive source (e.g. AWS's own
6
+ * documented `AKIAIOSFODNN7EXAMPLE` key, or `const password = 'testPass1234'`).
7
+ *
8
+ * Two tiers, by precision cost:
9
+ *
10
+ * - `standard` (safe for every pattern, including vendor-anchored keys):
11
+ * unambiguous markers that effectively never occur inside a real generated
12
+ * credential — `EXAMPLE`, `changeme`, `your_token_here`, all-`x` padding, …
13
+ *
14
+ * - `aggressive` (opt-in, used only by the low-precision generic / password
15
+ * assignment patterns): additionally treats common test-fixture words
16
+ * (`test`, `sample`, `password`, …) as placeholders. Scoped to those
17
+ * patterns so vendor-anchored keys keep full recall.
18
+ *
19
+ * Matching is substring-based on the lower-cased value. Markers are chosen to
20
+ * be long/specific enough that a real high-entropy secret will not contain them
21
+ * by chance.
22
+ */
23
+ Object.defineProperty(exports, "__esModule", { value: true });
24
+ exports.isSampleJwt = isSampleJwt;
25
+ exports.isNonSecretConnectionString = isNonSecretConnectionString;
26
+ exports.isPlaceholderSecret = isPlaceholderSecret;
27
+ /** Unambiguous placeholder markers — applied to all patterns. */
28
+ const STANDARD_MARKERS = [
29
+ 'example',
30
+ 'changeme',
31
+ 'change-me',
32
+ 'change_me',
33
+ 'placeholder',
34
+ 'redacted',
35
+ 'notreal',
36
+ 'not-a-real',
37
+ 'dummy',
38
+ 'yourtoken',
39
+ 'yourkey',
40
+ 'yourapikey',
41
+ 'your_token',
42
+ 'your-token',
43
+ 'your_key',
44
+ 'your-key',
45
+ 'your_api_key',
46
+ 'your-api-key',
47
+ 'insertyour',
48
+ 'insert_your',
49
+ 'replace_me',
50
+ 'replaceme',
51
+ 'loremipsum',
52
+ // Pure character repetition (e.g. `xxxxxxxx`, `00000000`) is handled by the
53
+ // low-variety check below rather than literal markers, so it does not clash
54
+ // with real keys that merely contain a short repeated run.
55
+ ];
56
+ /** Common test / fixture markers — applied only to generic assignment patterns. */
57
+ const AGGRESSIVE_MARKERS = [
58
+ 'test',
59
+ 'sample',
60
+ 'demo',
61
+ 'fake',
62
+ 'mock',
63
+ 'foobar',
64
+ 'password',
65
+ 'passw0rd',
66
+ 'secret',
67
+ 'hunter2',
68
+ 'qwerty',
69
+ 'letmein',
70
+ ];
71
+ /**
72
+ * A value made of one or two distinct characters (e.g. `xxxxxxxx`, `00000000`)
73
+ * is padding, never a real secret.
74
+ */
75
+ function isLowVariety(value) {
76
+ return value.length >= 8 && new Set(value).size <= 2;
77
+ }
78
+ /** Hosts that are never a remotely-exploitable credential leak. */
79
+ const LOCAL_HOSTS = new Set([
80
+ 'localhost',
81
+ '127.0.0.1',
82
+ '0.0.0.0',
83
+ '::1',
84
+ '[::1]',
85
+ 'host.docker.internal',
86
+ ]);
87
+ /** Reserved / non-routable TLD suffixes (RFC 6761 + docker/dev conventions). */
88
+ const LOCAL_TLD_SUFFIXES = [
89
+ '.local',
90
+ '.localhost',
91
+ '.test',
92
+ '.example',
93
+ '.invalid',
94
+ ];
95
+ /**
96
+ * Password tokens that are obviously defaults / placeholders rather than a
97
+ * real secret. Matched case-insensitively against the password component of a
98
+ * connection string. Deliberately scoped to the *password* — usernames like
99
+ * `admin` / `root` / `postgres` are extremely common in genuine leaks, so we
100
+ * never suppress based on the username alone.
101
+ */
102
+ const PLACEHOLDER_PASSWORDS = new Set([
103
+ 'password', 'passwd', 'pass', 'pwd', 'secret',
104
+ 'changeme', 'example', 'test', 'user', 'username',
105
+ 'root', 'admin', 'postgres', 'mysql', 'mongo', 'mongodb', 'redis',
106
+ 'db', 'database', 'prisma', 'identifier', 'key', 'token', 'name',
107
+ 'randompassword', 'yourpassword', 'mypassword',
108
+ ]);
109
+ /**
110
+ * Return `true` when a database/Redis connection string is **not** a real
111
+ * credential leak — i.e. it targets a local/dev/docker/example host, or uses
112
+ * obvious placeholder/default credentials.
113
+ *
114
+ * The exploitable secret in a DSN is the password against a *reachable* host.
115
+ * We suppress when either:
116
+ * 1. the host is local, a bare docker-compose service name, or a reserved
117
+ * TLD (`localhost`, `mysql`, `db.local`, …) — not remotely reachable; or
118
+ * 2. the password is a placeholder/default (`pass`, `PASSWORD`, `root:root`,
119
+ * `${DB_PASS}`, `<your-password>`, …).
120
+ *
121
+ * A real remote host with a real password (e.g.
122
+ * `postgres://app:8Fk2$mQ9z@db.prod.example-corp.com/main`) is **not**
123
+ * suppressed.
124
+ */
125
+ /**
126
+ * Recognise the canonical jwt.io / RFC 7519 sample token that is pasted into
127
+ * countless READMEs, OpenAPI specs, and tutorials. Its decoded payload carries
128
+ * the well-known sample claims (`sub: "1234567890"`, `name: "John Doe"`,
129
+ * `iat: 1516239022`). These are never real credentials.
130
+ */
131
+ function isSampleJwt(token) {
132
+ const parts = token.split('.');
133
+ if (parts.length < 2 || !parts[1])
134
+ return false;
135
+ let payload;
136
+ try {
137
+ payload = Buffer.from(parts[1], 'base64url').toString('utf-8');
138
+ }
139
+ catch {
140
+ return false;
141
+ }
142
+ return (/"sub"\s*:\s*"1234567890"/.test(payload) ||
143
+ /"name"\s*:\s*"John Doe"/.test(payload) ||
144
+ /\b1516239022\b/.test(payload));
145
+ }
146
+ function isNonSecretConnectionString(url) {
147
+ const m = /^[a-z][a-z0-9+.-]*:\/\/([^:@/\s]+):([^@/\s]+)@([^:/?\s]+)/i.exec(url);
148
+ if (!m)
149
+ return false;
150
+ const user = m[1];
151
+ const pass = m[2];
152
+ const host = m[3].toLowerCase();
153
+ // 1. Non-routable / local / docker-service / reserved-TLD host.
154
+ if (LOCAL_HOSTS.has(host))
155
+ return true;
156
+ if (LOCAL_TLD_SUFFIXES.some(suffix => host.endsWith(suffix)))
157
+ return true;
158
+ // Bare single-token host with no dot (and not a raw IPv4) is a docker-compose
159
+ // service name (`mysql`, `db`, `postgres`) — local to a compose network.
160
+ if (!host.includes('.') && !host.includes(':') && !/^\d+$/.test(host))
161
+ return true;
162
+ // 2. Placeholder / default password.
163
+ const p = pass.toLowerCase();
164
+ if (PLACEHOLDER_PASSWORDS.has(p))
165
+ return true;
166
+ if (user.toLowerCase() === p)
167
+ return true; // root:root, prisma:prisma
168
+ if (/^[A-Z][A-Z0-9_]*$/.test(pass))
169
+ return true; // USER:PASSWORD, DBPASS
170
+ if (pass.startsWith('$') || pass.startsWith('<') || pass.startsWith('{'))
171
+ return true; // ${DB_PASS}, <pw>
172
+ if (isPlaceholderSecret(pass, { aggressive: true }))
173
+ return true;
174
+ return false;
175
+ }
176
+ /**
177
+ * @returns `true` when `value` looks like a placeholder / example / test
178
+ * credential and should be suppressed.
179
+ */
180
+ function isPlaceholderSecret(value, opts = {}) {
181
+ if (!value)
182
+ return false;
183
+ const v = value.toLowerCase();
184
+ for (const marker of STANDARD_MARKERS) {
185
+ if (v.includes(marker))
186
+ return true;
187
+ }
188
+ if (isLowVariety(value))
189
+ return true;
190
+ if (opts.aggressive) {
191
+ for (const marker of AGGRESSIVE_MARKERS) {
192
+ if (v.includes(marker))
193
+ return true;
194
+ }
195
+ }
196
+ return false;
197
+ }
198
+ //# sourceMappingURL=placeholder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"placeholder.js","sourceRoot":"","sources":["../../src/utils/placeholder.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;;AAgHH,kCAcC;AAED,kEAwBC;AAMD,kDAoBC;AAhLD,iEAAiE;AACjE,MAAM,gBAAgB,GAAsB;IAC1C,SAAS;IACT,UAAU;IACV,WAAW;IACX,WAAW;IACX,aAAa;IACb,UAAU;IACV,SAAS;IACT,YAAY;IACZ,OAAO;IACP,WAAW;IACX,SAAS;IACT,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,UAAU;IACV,UAAU;IACV,cAAc;IACd,cAAc;IACd,YAAY;IACZ,aAAa;IACb,YAAY;IACZ,WAAW;IACX,YAAY;IACZ,4EAA4E;IAC5E,4EAA4E;IAC5E,2DAA2D;CAC5D,CAAC;AAEF,mFAAmF;AACnF,MAAM,kBAAkB,GAAsB;IAC5C,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,MAAM;IACN,QAAQ;IACR,UAAU;IACV,UAAU;IACV,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,SAAS;CACV,CAAC;AAEF;;;GAGG;AACH,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC;AACvD,CAAC;AAED,mEAAmE;AACnE,MAAM,WAAW,GAAwB,IAAI,GAAG,CAAC;IAC/C,WAAW;IACX,WAAW;IACX,SAAS;IACT,KAAK;IACL,OAAO;IACP,sBAAsB;CACvB,CAAC,CAAC;AAEH,gFAAgF;AAChF,MAAM,kBAAkB,GAAsB;IAC5C,QAAQ;IACR,YAAY;IACZ,OAAO;IACP,UAAU;IACV,UAAU;CACX,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,qBAAqB,GAAwB,IAAI,GAAG,CAAC;IACzD,UAAU,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ;IAC7C,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU;IACjD,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO;IACjE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM;IAChE,gBAAgB,EAAE,cAAc,EAAE,YAAY;CAC/C,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;GAeG;AACH;;;;;GAKG;AACH,SAAgB,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAChD,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CACL,0BAA0B,CAAC,IAAI,CAAC,OAAO,CAAC;QACxC,yBAAyB,CAAC,IAAI,CAAC,OAAO,CAAC;QACvC,gBAAgB,CAAC,IAAI,CAAC,OAAO,CAAC,CAC/B,CAAC;AACJ,CAAC;AAED,SAAgB,2BAA2B,CAAC,GAAW;IACrD,MAAM,CAAC,GAAG,4DAA4D,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjF,IAAI,CAAC,CAAC;QAAE,OAAO,KAAK,CAAC;IAErB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAClB,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;IAEhC,gEAAgE;IAChE,IAAI,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvC,IAAI,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1E,8EAA8E;IAC9E,yEAAyE;IACzE,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnF,qCAAqC;IACrC,MAAM,CAAC,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IAC7B,IAAI,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IAC9C,IAAI,IAAI,CAAC,WAAW,EAAE,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAY,2BAA2B;IACjF,IAAI,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,CAAM,wBAAwB;IAC9E,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,mBAAmB;IAC1G,IAAI,mBAAmB,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC;QAAE,OAAO,IAAI,CAAC;IAEjE,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,SAAgB,mBAAmB,CACjC,KAAa,EACb,OAAiC,EAAE;IAEnC,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;IAE9B,KAAK,MAAM,MAAM,IAAI,gBAAgB,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;IACtC,CAAC;IAED,IAAI,YAAY,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAErC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,KAAK,MAAM,MAAM,IAAI,kBAAkB,EAAE,CAAC;YACxC,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAAE,OAAO,IAAI,CAAC;QACtC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,102 @@
1
+ import type { DiagnosticCode } from '../diagnostics';
2
+ /**
3
+ * Heuristic safety checks for user-supplied regex patterns.
4
+ *
5
+ * Why this exists
6
+ * ---------------
7
+ * `VaultGuardConfig.extra_patterns[].regex` is compiled with `new RegExp(src, 'g')`
8
+ * and run against every line of every scanned file. A malicious or careless
9
+ * `.vault-guard.json` (anywhere in the repo, after the `loadConfig` git-boundary
10
+ * fix) can therefore implant a catastrophic-backtracking regex that pins the
11
+ * scanner CPU on the first file with the right shape.
12
+ *
13
+ * What this does (and does not) catch
14
+ * -----------------------------------
15
+ * This is a **conservative, dependency-free** static check:
16
+ *
17
+ * 1. Hard length cap (256 chars): real-world secret patterns are <100 chars;
18
+ * anything longer is suspicious and also bounds compile-time RAM use.
19
+ * 2. Quantifier-density cap (>25 of `* + ? {`): the academic ReDoS literature
20
+ * shows pathological patterns concentrate quantifiers; this is the same
21
+ * threshold `safe-regex` uses.
22
+ * 3. Nested-quantifier shape: `(…[*+]…)[*+]` — catches `(a+)+`, `(\d+)*`.
23
+ * 4. Alternation-quantifier shape: `(.|.)[*+]` — catches `(a|a)+`, `(\d|\d)*`.
24
+ *
25
+ * What this does NOT catch
26
+ * ------------------------
27
+ * - Cross-group backtracking like `(.*x)(y.*)` chains.
28
+ * - Pathological lookaheads.
29
+ * - Anything a determined attacker can hide behind character classes.
30
+ *
31
+ * Real defence in depth requires execution-time bounds (e.g. `re2`). That is
32
+ * tracked as a Phase 8 follow-up; this module is the pre-launch backstop.
33
+ *
34
+ * Users who need to bypass the heuristic for a known-safe pattern can set
35
+ * `extra_patterns_unsafe: true` in `.vault-guard.json`. The length cap still
36
+ * applies as a memory-use backstop even in unsafe mode.
37
+ */
38
+ /**
39
+ * Maximum allowed source length for user-provided regex strings.
40
+ *
41
+ * @remarks
42
+ * This cap is both a safety and performance bound. Real-world secret patterns
43
+ * are usually well under 100 characters; 256 leaves margin for legitimate
44
+ * patterns while rejecting pathological or accidental megaregex input.
45
+ */
46
+ export declare const REGEX_MAX_LENGTH = 256;
47
+ /**
48
+ * Maximum number of quantifier tokens (`* + ? {`) allowed in a user pattern.
49
+ *
50
+ * @remarks
51
+ * High quantifier density correlates strongly with catastrophic backtracking.
52
+ * The threshold intentionally matches common static-check heuristics.
53
+ */
54
+ export declare const REGEX_MAX_QUANTIFIERS = 25;
55
+ export type RegexSafetyReason = 'too_long' | 'too_many_quantifiers' | 'nested_quantifier' | 'alternation_quantifier' | 'invalid_syntax';
56
+ /**
57
+ * Canonical mapping from regex-safety rejections to diagnostics codes.
58
+ *
59
+ * Keep this mapping in one place so scan/reporting surfaces don't drift.
60
+ */
61
+ export declare const REGEX_REASON_TO_DIAGNOSTIC_CODE: Record<RegexSafetyReason, DiagnosticCode>;
62
+ export interface RegexSafetyResult {
63
+ ok: boolean;
64
+ reason?: RegexSafetyReason;
65
+ detail?: string;
66
+ }
67
+ /**
68
+ * Validate a user-supplied regex source string with heuristic ReDoS guards.
69
+ *
70
+ * @param source - Raw regex source from `.vault-guard.json` (without delimiters).
71
+ * @returns `ok: true` when accepted, otherwise `ok: false` with machine-readable
72
+ * `reason` and human-readable `detail` for diagnostics output.
73
+ */
74
+ export declare function validateRegexSafety(source: string): RegexSafetyResult;
75
+ /**
76
+ * Perform a length-only safety check.
77
+ *
78
+ * @param source - Raw regex source from `.vault-guard.json`.
79
+ * @returns `ok: false` with `reason: 'too_long'` when the source exceeds
80
+ * `REGEX_MAX_LENGTH`, otherwise `ok: true`.
81
+ *
82
+ * @remarks
83
+ * This is intentionally used even when `extra_patterns_unsafe: true` so there
84
+ * is always a hard memory backstop.
85
+ */
86
+ export declare function validateRegexLength(source: string): RegexSafetyResult;
87
+ /**
88
+ * Convert a regex safety rejection reason to the canonical diagnostic code.
89
+ *
90
+ * @param reason - Safety rejection identifier.
91
+ * @returns Stable diagnostics code for JSON/SARIF/text reporting.
92
+ */
93
+ export declare function mapRegexSafetyReasonToDiagnosticCode(reason: RegexSafetyReason): DiagnosticCode;
94
+ /**
95
+ * Safely map an untyped rejection reason string to a diagnostics code.
96
+ *
97
+ * @param reason - Rejection reason coming from runtime validation paths.
98
+ * @returns Canonical diagnostics code, defaulting to `pattern.redos_unsafe`
99
+ * when the reason is unknown.
100
+ */
101
+ export declare function mapPatternRejectionReasonToDiagnosticCode(reason: string): DiagnosticCode;
102
+ //# sourceMappingURL=regex-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex-safety.d.ts","sourceRoot":"","sources":["../../src/utils/regex-safety.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,gBAAgB,MAAM,CAAC;AAEpC;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,KAAK,CAAC;AAKxC,MAAM,MAAM,iBAAiB,GACzB,UAAU,GACV,sBAAsB,GACtB,mBAAmB,GACnB,wBAAwB,GACxB,gBAAgB,CAAC;AAErB;;;;GAIG;AACH,eAAO,MAAM,+BAA+B,EAAE,MAAM,CAAC,iBAAiB,EAAE,cAAc,CAMrF,CAAC;AAEF,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CAmCrE;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,iBAAiB,CASrE;AAED;;;;;GAKG;AACH,wBAAgB,oCAAoC,CAAC,MAAM,EAAE,iBAAiB,GAAG,cAAc,CAE9F;AAED;;;;;;GAMG;AACH,wBAAgB,yCAAyC,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAKxF"}
@@ -0,0 +1,193 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REGEX_REASON_TO_DIAGNOSTIC_CODE = exports.REGEX_MAX_QUANTIFIERS = exports.REGEX_MAX_LENGTH = void 0;
4
+ exports.validateRegexSafety = validateRegexSafety;
5
+ exports.validateRegexLength = validateRegexLength;
6
+ exports.mapRegexSafetyReasonToDiagnosticCode = mapRegexSafetyReasonToDiagnosticCode;
7
+ exports.mapPatternRejectionReasonToDiagnosticCode = mapPatternRejectionReasonToDiagnosticCode;
8
+ /**
9
+ * Heuristic safety checks for user-supplied regex patterns.
10
+ *
11
+ * Why this exists
12
+ * ---------------
13
+ * `VaultGuardConfig.extra_patterns[].regex` is compiled with `new RegExp(src, 'g')`
14
+ * and run against every line of every scanned file. A malicious or careless
15
+ * `.vault-guard.json` (anywhere in the repo, after the `loadConfig` git-boundary
16
+ * fix) can therefore implant a catastrophic-backtracking regex that pins the
17
+ * scanner CPU on the first file with the right shape.
18
+ *
19
+ * What this does (and does not) catch
20
+ * -----------------------------------
21
+ * This is a **conservative, dependency-free** static check:
22
+ *
23
+ * 1. Hard length cap (256 chars): real-world secret patterns are <100 chars;
24
+ * anything longer is suspicious and also bounds compile-time RAM use.
25
+ * 2. Quantifier-density cap (>25 of `* + ? {`): the academic ReDoS literature
26
+ * shows pathological patterns concentrate quantifiers; this is the same
27
+ * threshold `safe-regex` uses.
28
+ * 3. Nested-quantifier shape: `(…[*+]…)[*+]` — catches `(a+)+`, `(\d+)*`.
29
+ * 4. Alternation-quantifier shape: `(.|.)[*+]` — catches `(a|a)+`, `(\d|\d)*`.
30
+ *
31
+ * What this does NOT catch
32
+ * ------------------------
33
+ * - Cross-group backtracking like `(.*x)(y.*)` chains.
34
+ * - Pathological lookaheads.
35
+ * - Anything a determined attacker can hide behind character classes.
36
+ *
37
+ * Real defence in depth requires execution-time bounds (e.g. `re2`). That is
38
+ * tracked as a Phase 8 follow-up; this module is the pre-launch backstop.
39
+ *
40
+ * Users who need to bypass the heuristic for a known-safe pattern can set
41
+ * `extra_patterns_unsafe: true` in `.vault-guard.json`. The length cap still
42
+ * applies as a memory-use backstop even in unsafe mode.
43
+ */
44
+ /**
45
+ * Maximum allowed source length for user-provided regex strings.
46
+ *
47
+ * @remarks
48
+ * This cap is both a safety and performance bound. Real-world secret patterns
49
+ * are usually well under 100 characters; 256 leaves margin for legitimate
50
+ * patterns while rejecting pathological or accidental megaregex input.
51
+ */
52
+ exports.REGEX_MAX_LENGTH = 256;
53
+ /**
54
+ * Maximum number of quantifier tokens (`* + ? {`) allowed in a user pattern.
55
+ *
56
+ * @remarks
57
+ * High quantifier density correlates strongly with catastrophic backtracking.
58
+ * The threshold intentionally matches common static-check heuristics.
59
+ */
60
+ exports.REGEX_MAX_QUANTIFIERS = 25;
61
+ const NESTED_QUANTIFIER = /\([^()]*[*+][^()]*\)[*+]/;
62
+ const ALT_QUANTIFIER = /\([^()|]*\|[^()|]*\)[*+]/;
63
+ /**
64
+ * Canonical mapping from regex-safety rejections to diagnostics codes.
65
+ *
66
+ * Keep this mapping in one place so scan/reporting surfaces don't drift.
67
+ */
68
+ exports.REGEX_REASON_TO_DIAGNOSTIC_CODE = {
69
+ invalid_syntax: 'pattern.invalid',
70
+ too_long: 'pattern.too_long',
71
+ too_many_quantifiers: 'pattern.redos_unsafe',
72
+ nested_quantifier: 'pattern.redos_unsafe',
73
+ alternation_quantifier: 'pattern.redos_unsafe',
74
+ };
75
+ /**
76
+ * Validate a user-supplied regex source string with heuristic ReDoS guards.
77
+ *
78
+ * @param source - Raw regex source from `.vault-guard.json` (without delimiters).
79
+ * @returns `ok: true` when accepted, otherwise `ok: false` with machine-readable
80
+ * `reason` and human-readable `detail` for diagnostics output.
81
+ */
82
+ function validateRegexSafety(source) {
83
+ if (source.length > exports.REGEX_MAX_LENGTH) {
84
+ return {
85
+ ok: false,
86
+ reason: 'too_long',
87
+ detail: `regex source is ${source.length} chars (max ${exports.REGEX_MAX_LENGTH})`,
88
+ };
89
+ }
90
+ const quantifierCount = countQuantifiers(source);
91
+ if (quantifierCount > exports.REGEX_MAX_QUANTIFIERS) {
92
+ return {
93
+ ok: false,
94
+ reason: 'too_many_quantifiers',
95
+ detail: `regex contains ${quantifierCount} quantifiers (max ${exports.REGEX_MAX_QUANTIFIERS})`,
96
+ };
97
+ }
98
+ if (NESTED_QUANTIFIER.test(source)) {
99
+ return {
100
+ ok: false,
101
+ reason: 'nested_quantifier',
102
+ detail: 'nested quantifier of the form `(…[*+]…)[*+]` detected (catastrophic backtracking)',
103
+ };
104
+ }
105
+ if (ALT_QUANTIFIER.test(source)) {
106
+ return {
107
+ ok: false,
108
+ reason: 'alternation_quantifier',
109
+ detail: 'alternation under quantifier `(a|b)[*+]` detected (potential exponential backtracking)',
110
+ };
111
+ }
112
+ return { ok: true };
113
+ }
114
+ /**
115
+ * Perform a length-only safety check.
116
+ *
117
+ * @param source - Raw regex source from `.vault-guard.json`.
118
+ * @returns `ok: false` with `reason: 'too_long'` when the source exceeds
119
+ * `REGEX_MAX_LENGTH`, otherwise `ok: true`.
120
+ *
121
+ * @remarks
122
+ * This is intentionally used even when `extra_patterns_unsafe: true` so there
123
+ * is always a hard memory backstop.
124
+ */
125
+ function validateRegexLength(source) {
126
+ if (source.length > exports.REGEX_MAX_LENGTH) {
127
+ return {
128
+ ok: false,
129
+ reason: 'too_long',
130
+ detail: `regex source is ${source.length} chars (max ${exports.REGEX_MAX_LENGTH})`,
131
+ };
132
+ }
133
+ return { ok: true };
134
+ }
135
+ /**
136
+ * Convert a regex safety rejection reason to the canonical diagnostic code.
137
+ *
138
+ * @param reason - Safety rejection identifier.
139
+ * @returns Stable diagnostics code for JSON/SARIF/text reporting.
140
+ */
141
+ function mapRegexSafetyReasonToDiagnosticCode(reason) {
142
+ return exports.REGEX_REASON_TO_DIAGNOSTIC_CODE[reason];
143
+ }
144
+ /**
145
+ * Safely map an untyped rejection reason string to a diagnostics code.
146
+ *
147
+ * @param reason - Rejection reason coming from runtime validation paths.
148
+ * @returns Canonical diagnostics code, defaulting to `pattern.redos_unsafe`
149
+ * when the reason is unknown.
150
+ */
151
+ function mapPatternRejectionReasonToDiagnosticCode(reason) {
152
+ if (reason in exports.REGEX_REASON_TO_DIAGNOSTIC_CODE) {
153
+ return exports.REGEX_REASON_TO_DIAGNOSTIC_CODE[reason];
154
+ }
155
+ return 'pattern.redos_unsafe';
156
+ }
157
+ /**
158
+ * Count `* + ? {` quantifier characters outside character classes.
159
+ *
160
+ * Approximation only — doesn't fully tokenise the regex, just skips `[…]`
161
+ * blocks where these characters are literal. Good enough to flag pathological
162
+ * patterns without false-positiving on `[a-z?]` or `\?`.
163
+ */
164
+ function countQuantifiers(source) {
165
+ let count = 0;
166
+ let inClass = false;
167
+ let escape = false;
168
+ for (let i = 0; i < source.length; i++) {
169
+ const c = source[i];
170
+ if (escape) {
171
+ escape = false;
172
+ continue;
173
+ }
174
+ if (c === '\\') {
175
+ escape = true;
176
+ continue;
177
+ }
178
+ if (c === '[' && !inClass) {
179
+ inClass = true;
180
+ continue;
181
+ }
182
+ if (c === ']' && inClass) {
183
+ inClass = false;
184
+ continue;
185
+ }
186
+ if (inClass)
187
+ continue;
188
+ if (c === '*' || c === '+' || c === '?' || c === '{')
189
+ count++;
190
+ }
191
+ return count;
192
+ }
193
+ //# sourceMappingURL=regex-safety.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex-safety.js","sourceRoot":"","sources":["../../src/utils/regex-safety.ts"],"names":[],"mappings":"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"}