@aimarket/warden 0.0.1 → 0.4.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 (53) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/LICENSE +21 -0
  3. package/README-es.md +190 -0
  4. package/README-fr.md +190 -0
  5. package/README-ru.md +189 -0
  6. package/README-zh.md +173 -0
  7. package/README.md +179 -6
  8. package/dist/glob.d.ts +81 -0
  9. package/dist/glob.d.ts.map +1 -0
  10. package/dist/glob.js +180 -0
  11. package/dist/glob.js.map +1 -0
  12. package/dist/index.d.ts +106 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +218 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/jcs.d.ts +86 -0
  17. package/dist/jcs.d.ts.map +1 -0
  18. package/dist/jcs.js +296 -0
  19. package/dist/jcs.js.map +1 -0
  20. package/dist/logger.d.ts +10 -0
  21. package/dist/logger.d.ts.map +1 -0
  22. package/dist/logger.js +19 -0
  23. package/dist/logger.js.map +1 -0
  24. package/dist/origin.d.ts +25 -0
  25. package/dist/origin.d.ts.map +1 -0
  26. package/dist/origin.js +49 -0
  27. package/dist/origin.js.map +1 -0
  28. package/dist/pinning.d.ts +91 -0
  29. package/dist/pinning.d.ts.map +1 -0
  30. package/dist/pinning.js +227 -0
  31. package/dist/pinning.js.map +1 -0
  32. package/dist/sandbox.d.ts +38 -0
  33. package/dist/sandbox.d.ts.map +1 -0
  34. package/dist/sandbox.js +79 -0
  35. package/dist/sandbox.js.map +1 -0
  36. package/dist/sanitize.d.ts +38 -0
  37. package/dist/sanitize.d.ts.map +1 -0
  38. package/dist/sanitize.js +53 -0
  39. package/dist/sanitize.js.map +1 -0
  40. package/dist/static-scan.d.ts +110 -0
  41. package/dist/static-scan.d.ts.map +1 -0
  42. package/dist/static-scan.js +539 -0
  43. package/dist/static-scan.js.map +1 -0
  44. package/dist/threat-feed.d.ts +138 -0
  45. package/dist/threat-feed.d.ts.map +1 -0
  46. package/dist/threat-feed.js +546 -0
  47. package/dist/threat-feed.js.map +1 -0
  48. package/dist/types.d.ts +173 -0
  49. package/dist/types.d.ts.map +1 -0
  50. package/dist/types.js +11 -0
  51. package/dist/types.js.map +1 -0
  52. package/package.json +67 -9
  53. package/index.js +0 -6
@@ -0,0 +1,539 @@
1
+ import { createHash } from "node:crypto";
2
+ import { canonicalize } from "./jcs.js";
3
+ import { displaySafe } from "./sanitize.js";
4
+ import { silentLogger } from "./logger.js";
5
+ /** Prose surfaces: the default, and everything a noun-keyed rule may look at. */
6
+ const PROSE = ["description", "inputSchema"];
7
+ /** Prose plus the identifier - for phrase and hidden-payload rules. */
8
+ const ALL_SURFACES = ["name", "description", "inputSchema"];
9
+ // Imperative instructions aimed at the model — the classic injection tells.
10
+ const INJECTION_PATTERNS = [
11
+ { re: /\bignore\s+(?:all\s+|the\s+)?(?:previous|prior|above|preceding)\b/i, code: "TOOL_DEF_INJECTION", severity: "critical", tier: "block", surfaces: ALL_SURFACES, guards: ["mention"] },
12
+ { re: /\bdisregard\s+(?:all\s+|the\s+|any\s+)?(?:previous|prior|above|instructions?|rules?)\b/i, code: "TOOL_DEF_INJECTION", severity: "critical", tier: "block", surfaces: ALL_SURFACES, guards: ["mention"] },
13
+ // Demoted in v4. The survey found four real uses and all four were the
14
+ // OPPOSITE of concealment: "no refund is issued automatically … do not tell
15
+ // the user a refund is coming". Conscientious authors use the phrase to stop
16
+ // the model inventing reassurance. Blocking on it selected for exactly the
17
+ // servers that were being careful. A blocking rule needs a concealment target
18
+ // that refers to the tool's own action; the bare phrase does not carry one.
19
+ { re: /\bdo\s+not\s+(?:tell|inform|mention|reveal\s+to|notify)\s+(?:the\s+)?user\b/i, code: "TOOL_DEF_INJECTION", severity: "medium", tier: "advise", surfaces: ALL_SURFACES, guards: ["mention"] },
20
+ { re: /\bwithout\s+(?:telling|informing|asking)\s+(?:the\s+)?user\b/i, code: "TOOL_DEF_INJECTION", severity: "high", tier: "block", surfaces: ALL_SURFACES },
21
+ { re: /<\s*\/?\s*(?:system|instructions?|important)\s*>/i, code: "TOOL_DEF_INJECTION", severity: "high", tier: "block", surfaces: ALL_SURFACES },
22
+ // Demoted in v4. The comment here used to say this was "the blocking rule most
23
+ // likely to need a policy override"; the survey settled it — 15 findings across
24
+ // 6 servers, every one an LLM proxy, persona manager or agent-configuration
25
+ // tool that declares a `system` parameter because setting a system prompt is
26
+ // its entire job. The phrase is the domain's vocabulary, not the attack.
27
+ { re: /\b(?:system\s+prompt|developer\s+(?:message|prompt))\b/i, code: "TOOL_DEF_INJECTION", severity: "low", tier: "advise", surfaces: ALL_SURFACES },
28
+ // Ordinary English. Kept as a signal because it co-occurs with real poisoning,
29
+ // demoted because on its own it is noise: "You must supply a subject."
30
+ { re: /\byou\s+must\b/i, code: "TOOL_DEF_IMPERATIVE", severity: "low", tier: "advise", surfaces: ALL_SURFACES },
31
+ { re: /\binstead\s+of\b/i, code: "TOOL_DEF_IMPERATIVE", severity: "info", tier: "advise", surfaces: ALL_SURFACES },
32
+ ];
33
+ // Data-exfiltration phrasing.
34
+ const EXFIL_PATTERNS = [
35
+ // Demoted in v4. An attacker does not name the attack; a defender names it in
36
+ // every sentence. All three of the survey's hits were defensive tools — an MCP
37
+ // endpoint scanner, an injection scanner, and a policy builder whose `enum` is
38
+ // `["exfiltration", "recon_then_destroy", …]`. The anchored "send X to
39
+ // <external destination>" rules below carry the blocking weight instead.
40
+ { re: /\bexfiltrat\w*/i, code: "TOOL_DEF_EXFIL", severity: "medium", tier: "advise", surfaces: ALL_SURFACES, guards: ["mention"] },
41
+ // Anchored on an EXTERNAL destination. Unanchored, this matched "Send the
42
+ // message to the recipient" in any honest email or webhook tool.
43
+ {
44
+ re: /\b(?:send|post|forward|relay)\s+(?:it|them|this|the\s+\w+|all|results?|output|data|contents?)\s+to\s+(?:https?:\/\/|\b[\w-]+(?:\.[\w-]+)*\.[a-z]{2,}\b)/i,
45
+ code: "TOOL_DEF_EXFIL",
46
+ severity: "high",
47
+ tier: "block",
48
+ surfaces: ALL_SURFACES,
49
+ },
50
+ { re: /\b(?:post|send|put)\s+to\s+https?:\/\//i, code: "TOOL_DEF_EXFIL", severity: "critical", tier: "block", surfaces: ALL_SURFACES },
51
+ { re: /\bupload\b[\s\S]{0,40}\bto\s+(?:https?:\/\/|[\w.-]+\.[a-z]{2,})/i, code: "TOOL_DEF_EXFIL", severity: "high", tier: "block", surfaces: ALL_SURFACES },
52
+ ];
53
+ // Secrets. Naming a credential PARAMETER is what normal tools do; demanding the
54
+ // material that is never a parameter is not.
55
+ //
56
+ // The discriminator is the VERB, not the noun. "Requires a personal access token
57
+ // with repo scope" describes an input. "read the user's api_key from the .env
58
+ // file" instructs the model to go and get one. Tiering on the noun alone is what
59
+ // blocked every real server, and dropping the noun rules entirely would have let
60
+ // a harvest instruction through whenever it omitted an injection phrase.
61
+ const SECRET_PATTERNS = [
62
+ {
63
+ // The gap may no longer cross a sentence or a JSON string boundary. It used
64
+ // to be `[\s\S]{0,30}`, which matched "read an open or sealed run (pass
65
+ // api_key" — a verb in prose reaching into the next field's parameter name.
66
+ re: /\b(?:read|extract|retrieve|fetch|obtain|dump|reveal|collect|harvest|grab|copy|print)\s[^.;"\n]{0,30}?\b(?:api[_\s-]?key|access[_\s-]?token|bearer\s+token|credential|password|passwd|secret|\.env\b|environment\s+variable)/i,
67
+ code: "TOOL_DEF_SECRET_HARVEST",
68
+ severity: "critical",
69
+ tier: "block",
70
+ // Phrase-keyed: the verb must be followed by whitespace, so `read_api_key`
71
+ // as an identifier cannot match while `read api_key` in a name can.
72
+ surfaces: ALL_SURFACES,
73
+ // "never store secrets", "never collect card data", "does not reveal or mint
74
+ // a standalone agent credential" — three servers blocked for promising in
75
+ // writing not to do this.
76
+ guards: ["polarity", "harvestTarget"],
77
+ },
78
+ // Severity lowered from critical to high in v4: still over the default block
79
+ // threshold, but no longer zeroing the gate score outright. One noun in a
80
+ // schema template shared by 377 tools should not read as "this server is
81
+ // maximally compromised" — and with the polarity guard, the template that
82
+ // caused it ("do not … include private key material") no longer matches at all.
83
+ { re: /\bprivate[_\s-]?key\b/i, code: "TOOL_DEF_SECRET_REQUEST", severity: "high", tier: "block", surfaces: PROSE, guards: ["polarity", "detection", "identifierFragment"] },
84
+ { re: /\bseed[_\s-]?phrase\b|\bmnemonic\b/i, code: "TOOL_DEF_SECRET_REQUEST", severity: "high", tier: "block", surfaces: PROSE, guards: ["polarity", "mention", "detection", "identifierFragment"] },
85
+ { re: /~\/\.ssh|\bid_rsa\b|\.ssh\/[\w.-]+/i, code: "TOOL_DEF_SECRET_REQUEST", severity: "high", tier: "block", surfaces: PROSE, guards: ["polarity", "publicKeyPath"] },
86
+ // Advisory: these are ordinary parameter names and ordinary setup prose.
87
+ { re: /\bapi[_\s-]?key\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "low", tier: "advise", surfaces: PROSE },
88
+ { re: /\bcredentials?\b|\baccess[_\s-]?token\b|\bbearer\s+token\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "low", tier: "advise", surfaces: PROSE },
89
+ { re: /\bsecret(?:s)?\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "low", tier: "advise", surfaces: PROSE },
90
+ { re: /\bpassword\b|\bpasswd\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "medium", tier: "advise", surfaces: PROSE },
91
+ { re: /(?:^|[^.\w])\.env\b|\benvironment\s+variables?\b/i, code: "TOOL_DEF_ENV_REFERENCE", severity: "medium", tier: "advise", surfaces: PROSE },
92
+ ];
93
+ // Dangerous URL schemes embedded in text.
94
+ const URL_SCHEME_PATTERNS = [
95
+ // A `data:` URI with no payload behind it is the format being documented —
96
+ // `"example": "<url> OR data:image/png;base64,..."` on every image API.
97
+ { re: /\bdata:[\w/+.-]+;base64,/i, code: "TOOL_DEF_DATA_URL", severity: "high", tier: "block", surfaces: ALL_SURFACES, guards: ["payload", "mention"] },
98
+ // Case-SENSITIVE since v4. Under /i this matched the word "JavaScript"
99
+ // followed by a colon, i.e. every language list ever written:
100
+ // "TypeScript/JavaScript: *.spec/test.{ts,js}".
101
+ { re: /\bjavascript:/, code: "TOOL_DEF_DATA_URL", severity: "high", tier: "block", surfaces: ALL_SURFACES, guards: ["uri", "mention"] },
102
+ ];
103
+ // Hidden payloads. Part of the rule table (and therefore the digest) rather than
104
+ // special cases in the scan loop.
105
+ const PAYLOAD_PATTERNS = [
106
+ {
107
+ // Standard (RFC 4648 §4) AND URL-safe (§5) base64, padded or not — JWTs and
108
+ // web payloads commonly omit padding.
109
+ re: /[A-Za-z0-9+/_-]{120,}={0,2}/,
110
+ code: "TOOL_DEF_BASE64_BLOB",
111
+ severity: "high",
112
+ tier: "block",
113
+ surfaces: ALL_SURFACES,
114
+ note: "contains a long base64-encoded blob — possible hidden payload",
115
+ guards: ["blob"],
116
+ },
117
+ {
118
+ // U+200B–200F, U+202A–202E, U+2060, U+FEFF. Built from a \u-escaped string so
119
+ // the source stays reviewable (the characters are, by definition, invisible).
120
+ re: new RegExp("[\\u200B-\\u200F\\u202A-\\u202E\\u2060\\uFEFF]"),
121
+ code: "TOOL_DEF_HIDDEN_UNICODE",
122
+ severity: "high",
123
+ tier: "block",
124
+ surfaces: ALL_SURFACES,
125
+ note: "contains zero-width or bidi control characters hiding text from review",
126
+ guards: ["zeroWidth"],
127
+ },
128
+ ];
129
+ /**
130
+ * Words that flip the meaning of a credential noun near them.
131
+ *
132
+ * "Never send a private key" and "send a private key" differ by one of these and
133
+ * nothing else, and a noun-keyed rule reads them identically. In the survey this
134
+ * single distinction accounted for 390 of 492 blocking findings.
135
+ */
136
+ const REFUSAL = /\b(?:never|not|no|non|without|nor|refus\w*|forbid\w*|prohibit\w*|exclud\w*|reject\w*|don'?t|doesn'?t|won'?t|cannot|can'?t|unnecessary|none)\b/i;
137
+ /**
138
+ * How far a guard looks for context, and what stops it.
139
+ *
140
+ * Bounded because a refusal three sentences away is not about this noun, and
141
+ * stopped at clause boundaries for the same reason. `","` is in the stop set
142
+ * because on the schema surface the text is JSON: two adjacent field descriptions
143
+ * are as unrelated as two sentences, and a 120-character window would otherwise
144
+ * read one field's negation as covering the next field's noun.
145
+ */
146
+ const CONTEXT_SPAN = 120;
147
+ /** Text either side of the match, cut at the nearest clause boundary. */
148
+ function clauseAround(text, start, end) {
149
+ let a = start;
150
+ const floor = Math.max(0, start - CONTEXT_SPAN);
151
+ while (a > floor && !isClauseStop(text, a - 1))
152
+ a--;
153
+ let b = end;
154
+ const ceil = Math.min(text.length, end + CONTEXT_SPAN);
155
+ while (b < ceil && !isClauseStop(text, b))
156
+ b++;
157
+ return { before: text.slice(a, start), after: text.slice(end, b) };
158
+ }
159
+ function isClauseStop(text, i) {
160
+ const c = text[i];
161
+ if (c === "." || c === ";" || c === "!" || c === "?" || c === "\n")
162
+ return true;
163
+ // JSON field boundary: `","` between two schema descriptions.
164
+ return c === '"' && text[i + 1] === ",";
165
+ }
166
+ /** Is the match wrapped in quotes or backticks — i.e. cited rather than said? */
167
+ function isQuoted(text, start, end) {
168
+ for (const q of ["'", '"', "`"]) {
169
+ const open = text.lastIndexOf(q, start - 1);
170
+ if (open < 0)
171
+ continue;
172
+ const close = text.indexOf(q, end);
173
+ if (close < 0)
174
+ continue;
175
+ // A citation is short. A whole paragraph between two apostrophes is not one.
176
+ if (close - open <= 120 && !text.slice(open + 1, close).includes("\n"))
177
+ return true;
178
+ }
179
+ return false;
180
+ }
181
+ /** Shannon entropy in bits per character. */
182
+ function entropy(sample) {
183
+ const counts = new Map();
184
+ for (const ch of sample)
185
+ counts.set(ch, (counts.get(ch) ?? 0) + 1);
186
+ let h = 0;
187
+ for (const n of counts.values()) {
188
+ const pr = n / sample.length;
189
+ h -= pr * Math.log2(pr);
190
+ }
191
+ return h;
192
+ }
193
+ /**
194
+ * Zero-width characters that are orthography, not concealment.
195
+ *
196
+ * U+200C ZERO WIDTH NON-JOINER is a REQUIRED letter-form control in Persian,
197
+ * Arabic and several Indic scripts: `بخشنامه‌ها` is spelled with one. The survey
198
+ * blocked an Iranian legal-calculation server five times for writing its own
199
+ * language. U+200B, U+FEFF and the bidi overrides have no such role and stay
200
+ * blocking.
201
+ */
202
+ const SCRIPT_NEEDING_JOINER_CONTROL = /[\u0600-\u06FF\u0750-\u077F\u08A0-\u08FF\u0900-\u0DFF\uFB50-\uFDFF\uFE70-\uFEFE]/;
203
+ const GUARDS = {
204
+ /** A credential noun inside a refusal is a promise, not a request. */
205
+ polarity(m, text) {
206
+ // The cue can sit INSIDE the match when the rule spans a verb and a noun:
207
+ // "read it, so never store secret" is one TOOL_DEF_SECRET_HARVEST match.
208
+ if (REFUSAL.test(m[0]))
209
+ return "refusal cue inside the match";
210
+ const { before, after } = clauseAround(text, m.index, m.index + m[0].length);
211
+ if (REFUSAL.test(before))
212
+ return "refusal cue before the match in the same clause";
213
+ if (REFUSAL.test(after))
214
+ return "refusal cue after the match in the same clause";
215
+ return null;
216
+ },
217
+ /**
218
+ * A phrase in quotes, in backticks, or as a bare JSON enum value is a mention.
219
+ *
220
+ * Four of the survey's blocked servers were security tools listing the attacks
221
+ * they detect — one of them in an `enum` of `["exfiltration", …]`.
222
+ */
223
+ mention(m, text, surface) {
224
+ const start = m.index;
225
+ const end = start + m[0].length;
226
+ if (isQuoted(text, start, end))
227
+ return "match is quoted or in backticks — a citation, not an instruction";
228
+ if (surface === "inputSchema" && text[start - 1] === '"' && text[end] === '"') {
229
+ return "match is a complete JSON string token — an enum value or field name";
230
+ }
231
+ return null;
232
+ },
233
+ /**
234
+ * `javascript:` as a URI, not as the name of a language.
235
+ *
236
+ * The rule is case-sensitive now, which alone removes "TypeScript/JavaScript:"
237
+ * from every language list on earth. A scheme is also followed immediately by
238
+ * its payload, so a space after the colon means a label.
239
+ */
240
+ uri(m, text) {
241
+ const after = text.slice(m.index + m[0].length);
242
+ // A scheme followed by punctuation is a list item or a label: "Filters out
243
+ // javascript:, mailto:, data: schemes".
244
+ if (after === "" || /^[\s"'`)\],;.]/.test(after))
245
+ return "no URI payload after the scheme — a label, not a link";
246
+ return null;
247
+ },
248
+ /** A `data:` URI that carries no payload is documentation of the format. */
249
+ payload(m, text) {
250
+ const rest = text.slice(m.index + m[0].length);
251
+ const body = /^[A-Za-z0-9+/=]*/.exec(rest)?.[0] ?? "";
252
+ if (body.length < 32)
253
+ return `only ${body.length} payload characters — a placeholder or an example`;
254
+ return null;
255
+ },
256
+ /**
257
+ * A long run of base64-alphabet characters that is structure, not a payload.
258
+ *
259
+ * `/` is in the base64 alphabet, so a deeply nested JSON Schema pointer —
260
+ * `#/properties/flow/items/anyOf/2/properties/outcomes/items` — reads as a
261
+ * blob. Real encoded data is near-uniform over the alphabet; identifiers and
262
+ * paths are not, and they repeat words a reviewer can read.
263
+ */
264
+ blob(m) {
265
+ const hit = m[0];
266
+ if (/properties|items|definitions|anyOf|allOf|oneOf|\$defs/i.test(hit)) {
267
+ return "match is a JSON Schema pointer, not an encoded payload";
268
+ }
269
+ const h = entropy(hit);
270
+ if (h < BLOB_MIN_ENTROPY)
271
+ return `entropy ${h.toFixed(2)} bits/char is below the ${BLOB_MIN_ENTROPY} floor — structure, not data`;
272
+ return null;
273
+ },
274
+ zeroWidth(m, text) {
275
+ const ch = m[0];
276
+ if (ch !== "\u200C" && ch !== "\u200D")
277
+ return null;
278
+ const prev = text[m.index - 1] ?? "";
279
+ const next = text[m.index + 1] ?? "";
280
+ if (SCRIPT_NEEDING_JOINER_CONTROL.test(prev) || SCRIPT_NEEDING_JOINER_CONTROL.test(next)) {
281
+ return "joiner control adjacent to a script that requires it — orthography, not concealment";
282
+ }
283
+ return null;
284
+ },
285
+ /**
286
+ * A credential noun that is a FRAGMENT of a longer identifier is that
287
+ * identifier's name.
288
+ *
289
+ * `bip39-mnemonic-checksum` sat in a comma-separated list of several hundred
290
+ * calculator names and blocked a generic lookup gateway four times. A schema
291
+ * field genuinely called `seed_phrase` still matches, because there the rule
292
+ * consumes the whole token rather than part of it.
293
+ */
294
+ identifierFragment(m, text) {
295
+ const start = m.index;
296
+ const end = start + m[0].length;
297
+ let a = start;
298
+ while (a > 0 && /[\w.-]/.test(text[a - 1]))
299
+ a--;
300
+ let b = end;
301
+ while (b < text.length && /[\w.-]/.test(text[b]))
302
+ b++;
303
+ const token = text.slice(a, b);
304
+ if (token.length === m[0].length)
305
+ return null;
306
+ if (!/[-.]/.test(token))
307
+ return null;
308
+ return `match is part of the longer identifier "${token.slice(0, 60)}"`;
309
+ },
310
+ /**
311
+ * A secret named as the OBJECT OF DETECTION is not a secret being requested.
312
+ *
313
+ * The survey blocked a secret scanner on "Detect likely leaked API keys,
314
+ * tokens, private-key headers, JWTs" and an injection scanner on its own
315
+ * taxonomy. Naming what you look for is the defender's whole job.
316
+ */
317
+ detection(m, text) {
318
+ const { before } = clauseAround(text, m.index, m.index + m[0].length);
319
+ if (/\b(?:detect\w*|scan\w*|identif\w*|find\w*|report\w*|flag\w*|audit\w*|inspect\w*|check(?:s|ed|ing)?\s+for|look(?:s|ed|ing)?\s+for|leaked?)\b/i.test(before)) {
320
+ return "secret named as the object of detection, not requested";
321
+ }
322
+ return null;
323
+ },
324
+ /**
325
+ * A harvest instruction says WHOSE secret, or WHERE it lives.
326
+ *
327
+ * The rule's own comment always claimed this: "read the user's api_key from
328
+ * the .env file". Without the constraint it also matched "Obtain a permanent
329
+ * anonymous API key" and "obtain a visitor access token" — tools that ISSUE
330
+ * you a credential, which is the opposite transaction.
331
+ */
332
+ harvestTarget(m) {
333
+ const hit = m[0];
334
+ if (/\b(?:the\s+user'?s?|user'?s|your|their|his|her|its|my|from|out\s+of|stored|saved|existing)\b/i.test(hit))
335
+ return null;
336
+ if (/[~/\\]|\.env\b|environment/i.test(hit))
337
+ return null;
338
+ return "no owner or location for the secret — reads as a credential being issued, not taken";
339
+ },
340
+ /** `.ssh/authorized_keys` and `id_ed25519.pub` are public by definition. */
341
+ publicKeyPath(m, text) {
342
+ // A RAW forward window, not a clause: the giveaway is the extension, and
343
+ // `.pub` begins with the character clauseAround treats as a sentence end.
344
+ const end = m.index + m[0].length;
345
+ const hit = m[0] + text.slice(end, end + 48);
346
+ if (/authorized_keys|known_hosts|\.pub\b/i.test(hit))
347
+ return "path names public key material";
348
+ return null;
349
+ },
350
+ };
351
+ /** Entropy floor for {@link GUARDS.payload}-style blob detection. */
352
+ const BLOB_MIN_ENTROPY = 4.2;
353
+ const RULES = [
354
+ ...INJECTION_PATTERNS,
355
+ ...EXFIL_PATTERNS,
356
+ ...SECRET_PATTERNS,
357
+ ...URL_SCHEME_PATTERNS,
358
+ ...PAYLOAD_PATTERNS,
359
+ ];
360
+ /**
361
+ * Ruleset version. Bump on ANY change to the table above — a scan result is only
362
+ * comparable to another scan made under the same version and digest.
363
+ *
364
+ * 1 — single tier; credential parameter names blocked real servers.
365
+ * 2 — block/advise tiers; exfil "send … to" anchored on an external destination;
366
+ * TOOL_DEF_SECRET_HARVEST added so demoting the credential nouns does not
367
+ * open a hole; advisory findings no longer affect the score.
368
+ * 3 — rules gained `surfaces`, and the tool NAME became a scanned surface. Until
369
+ * v3 the name was scanned by nothing, so zero-width characters, a base64 blob
370
+ * or an injection phrase in the one field that reaches the model first went
371
+ * entirely unreported. Noun-keyed rules stay off the name on purpose: they
372
+ * match ordinary identifiers, and refusing `sign_with_private_key` would be
373
+ * the v1 calibration error committed on a new surface.
374
+ * 4 — calibrated against 1 108 live public MCP servers (docs/mcp-survey.md). v3
375
+ * blocked 50 of them and only 4 held up on review, so v4 adds context
376
+ * GUARDS — polarity, quotation, URI form, payload length, entropy, script
377
+ * adjacency — and demotes four blocking rules the survey showed were
378
+ * selecting for honest servers: the bare `exfiltrat*` noun, `system prompt`,
379
+ * `do not tell the user`, and (in severity only) the credential nouns. A
380
+ * rule's guards are part of this table and therefore of the digest.
381
+ */
382
+ export const STATIC_SCAN_RULESET_VERSION = "4";
383
+ const SEVERITY_RANK = {
384
+ info: 0,
385
+ low: 1,
386
+ medium: 2,
387
+ high: 3,
388
+ critical: 4,
389
+ };
390
+ /** Penalty applied to the gate score per worst BLOCKING severity found. */
391
+ const SEVERITY_PENALTY = {
392
+ info: 0,
393
+ low: 0.1,
394
+ medium: 0.3,
395
+ high: 0.6,
396
+ critical: 1,
397
+ };
398
+ /**
399
+ * The rule table plus its digest, so a scan result stays checkable after the
400
+ * rules change.
401
+ *
402
+ * Sorted, so the digest depends on the rules and not on the order they happen to
403
+ * be declared in — and sorted by CODE-UNIT comparison, not `localeCompare`: the
404
+ * digest is a cross-machine identifier, and a locale-dependent collation would
405
+ * make the same rule table digest differently on a differently-configured host,
406
+ * which is exactly the divergence the digest exists to detect. The preimage is
407
+ * the RFC 8785 canonical form (see ./jcs.ts) so this file does not invent a
408
+ * second serialization of its own.
409
+ */
410
+ export function staticScanRuleset() {
411
+ const rules = RULES.map((r) => ({
412
+ code: r.code,
413
+ severity: r.severity,
414
+ tier: r.tier,
415
+ surfaces: [...r.surfaces],
416
+ source: r.re.source,
417
+ flags: r.re.flags,
418
+ guards: [...(r.guards ?? [])],
419
+ })).sort((a, b) => cmp(a.code, b.code) || cmp(a.source, b.source) || cmp(a.flags, b.flags));
420
+ const preimage = canonicalize({ version: STATIC_SCAN_RULESET_VERSION, rules });
421
+ const digest = `sha256-${createHash("sha256").update(preimage, "utf8").digest("base64")}`;
422
+ return { version: STATIC_SCAN_RULESET_VERSION, digest, rules };
423
+ }
424
+ /** Code-unit comparison. See staticScanRuleset for why not localeCompare. */
425
+ function cmp(a, b) {
426
+ return a < b ? -1 : a > b ? 1 : 0;
427
+ }
428
+ /** Just the identity of the rule table, for embedding in a verdict. */
429
+ export function staticScanRulesetRef() {
430
+ const { version, digest } = staticScanRuleset();
431
+ return { version, digest };
432
+ }
433
+ export class StaticScanGate {
434
+ name = "static-scan";
435
+ log;
436
+ /**
437
+ * @param log where dropped matches are reported. A guard silently discarding a
438
+ * finding is the one behaviour in this gate that cannot be seen in the
439
+ * verdict, so it is the one that most needs a debug line.
440
+ */
441
+ constructor(log = silentLogger()) {
442
+ this.log = log.child("static-scan");
443
+ }
444
+ async evaluate(input) {
445
+ const findings = [];
446
+ for (const tool of input.tools) {
447
+ const schemaText = safeStringifySchema(tool.inputSchema);
448
+ // The name is an identifier, the description is prose, the schema text is
449
+ // field names + descriptions + enums. All three reach the model; each rule
450
+ // declares which of them it is meaningful against (see Surface).
451
+ const haystacks = [
452
+ { text: tool.name ?? "", surface: "name", where: "name" },
453
+ { text: tool.description ?? "", surface: "description", where: "description" },
454
+ { text: schemaText, surface: "inputSchema", where: "input schema" },
455
+ ];
456
+ // The name is quoted back in every message, so it is escaped once here
457
+ // rather than at each call site. `finding.tool` keeps the raw name: it is
458
+ // the key the host filters its tool list with.
459
+ const shown = displaySafe(tool.name);
460
+ for (const { text, surface, where } of haystacks) {
461
+ for (const rule of RULES) {
462
+ if (!rule.surfaces.includes(surface))
463
+ continue;
464
+ const m = matchOf(rule.re, text);
465
+ if (!m)
466
+ continue;
467
+ const dropped = rule.guards?.map((g) => GUARDS[g](m, text, surface)).find((r) => r !== null);
468
+ if (dropped) {
469
+ this.log.debug(`static-scan: dropped ${rule.code} on "${shown}" ${where} — ${dropped}`);
470
+ continue;
471
+ }
472
+ // The matched text goes into the message. Without it the reader gets
473
+ // "matches TOOL_DEF_SECRET_HARVEST signature (\b(?:read|extract|…)" and
474
+ // cannot tell which alternative fired, or on what — which is most of
475
+ // the work of judging whether a finding is real.
476
+ const span = displaySafe(m[0], SPAN_MAX);
477
+ const finding = {
478
+ gate: this.name,
479
+ severity: rule.severity,
480
+ code: rule.code,
481
+ message: rule.note
482
+ ? `Tool "${shown}" ${where} ${rule.note} — at "${span}".`
483
+ : `Tool "${shown}" ${where} matches ${rule.code} signature (${describe(rule.re)}) at "${span}".`,
484
+ tool: tool.name,
485
+ };
486
+ if (rule.tier === "advise")
487
+ finding.advisory = true;
488
+ findings.push(finding);
489
+ }
490
+ }
491
+ }
492
+ return { findings, score: scoreFor(findings) };
493
+ }
494
+ }
495
+ /**
496
+ * 1 minus the penalty for the worst BLOCKING severity found; clamped to [0,1].
497
+ *
498
+ * Advisory findings are excluded on purpose. The composite is presented to users
499
+ * as a safety score, and a credential parameter name is not a safety defect —
500
+ * letting it drag the number down made a clean server look like a compromised one.
501
+ */
502
+ function scoreFor(findings) {
503
+ let worst = "info";
504
+ for (const f of findings) {
505
+ if (f.advisory)
506
+ continue;
507
+ if (SEVERITY_RANK[f.severity] > SEVERITY_RANK[worst])
508
+ worst = f.severity;
509
+ }
510
+ const score = 1 - SEVERITY_PENALTY[worst];
511
+ return Math.max(0, Math.min(1, score));
512
+ }
513
+ /** Deterministic, total stringify of a JSON schema for scanning. */
514
+ function safeStringifySchema(schema) {
515
+ try {
516
+ return JSON.stringify(schema) ?? "";
517
+ }
518
+ catch {
519
+ return String(schema ?? "");
520
+ }
521
+ }
522
+ /** Short human label for a signature regex, for the finding message. */
523
+ function describe(re) {
524
+ return re.source.length > 48 ? `${re.source.slice(0, 45)}…` : re.source;
525
+ }
526
+ /** How much of the matched text a finding quotes back. */
527
+ const SPAN_MAX = 80;
528
+ /**
529
+ * First match, with its position, without mutating the shared rule regex.
530
+ *
531
+ * The rules are module-level constants reused for every tool, so `lastIndex` must
532
+ * never be left behind on them: a `g`-flagged rule would silently start scanning
533
+ * the next tool from wherever the previous match ended. None of them carry `g`
534
+ * today; this makes that a non-issue rather than an invariant to remember.
535
+ */
536
+ function matchOf(re, text) {
537
+ return new RegExp(re.source, re.flags.replace(/[gy]/g, "")).exec(text);
538
+ }
539
+ //# sourceMappingURL=static-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static-scan.js","sourceRoot":"","sources":["../src/static-scan.ts"],"names":[],"mappings":"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"}