@aimarket/warden 0.3.0 → 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.
@@ -1,25 +1,43 @@
1
1
  import { createHash } from "node:crypto";
2
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"];
3
9
  // Imperative instructions aimed at the model — the classic injection tells.
4
10
  const INJECTION_PATTERNS = [
5
- { re: /\bignore\s+(?:all\s+|the\s+)?(?:previous|prior|above|preceding)\b/i, code: "TOOL_DEF_INJECTION", severity: "critical", tier: "block" },
6
- { re: /\bdisregard\s+(?:all\s+|the\s+|any\s+)?(?:previous|prior|above|instructions?|rules?)\b/i, code: "TOOL_DEF_INJECTION", severity: "critical", tier: "block" },
7
- { re: /\bdo\s+not\s+(?:tell|inform|mention|reveal\s+to|notify)\s+(?:the\s+)?user\b/i, code: "TOOL_DEF_INJECTION", severity: "critical", tier: "block" },
8
- { re: /\bwithout\s+(?:telling|informing|asking)\s+(?:the\s+)?user\b/i, code: "TOOL_DEF_INJECTION", severity: "high", tier: "block" },
9
- { re: /<\s*\/?\s*(?:system|instructions?|important)\s*>/i, code: "TOOL_DEF_INJECTION", severity: "high", tier: "block" },
10
- // A tool DEFINITION that talks about the model's own instructions is arguing
11
- // with the system prompt, not describing a capability. Honest servers describe
12
- // user-supplied prompts instead. This is the blocking rule most likely to need
13
- // a policy override — a prompt-management server may legitimately trip it.
14
- { re: /\b(?:system\s+prompt|developer\s+(?:message|prompt))\b/i, code: "TOOL_DEF_INJECTION", severity: "high", tier: "block" },
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 },
15
28
  // Ordinary English. Kept as a signal because it co-occurs with real poisoning,
16
29
  // demoted because on its own it is noise: "You must supply a subject."
17
- { re: /\byou\s+must\b/i, code: "TOOL_DEF_IMPERATIVE", severity: "low", tier: "advise" },
18
- { re: /\binstead\s+of\b/i, code: "TOOL_DEF_IMPERATIVE", severity: "info", tier: "advise" },
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 },
19
32
  ];
20
33
  // Data-exfiltration phrasing.
21
34
  const EXFIL_PATTERNS = [
22
- { re: /\bexfiltrat\w*/i, code: "TOOL_DEF_EXFIL", severity: "critical", tier: "block" },
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"] },
23
41
  // Anchored on an EXTERNAL destination. Unanchored, this matched "Send the
24
42
  // message to the recipient" in any honest email or webhook tool.
25
43
  {
@@ -27,9 +45,10 @@ const EXFIL_PATTERNS = [
27
45
  code: "TOOL_DEF_EXFIL",
28
46
  severity: "high",
29
47
  tier: "block",
48
+ surfaces: ALL_SURFACES,
30
49
  },
31
- { re: /\b(?:post|send|put)\s+to\s+https?:\/\//i, code: "TOOL_DEF_EXFIL", severity: "critical", tier: "block" },
32
- { re: /\bupload\b[\s\S]{0,40}\bto\s+(?:https?:\/\/|[\w.-]+\.[a-z]{2,})/i, code: "TOOL_DEF_EXFIL", severity: "high", tier: "block" },
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 },
33
52
  ];
34
53
  // Secrets. Naming a credential PARAMETER is what normal tools do; demanding the
35
54
  // material that is never a parameter is not.
@@ -41,25 +60,45 @@ const EXFIL_PATTERNS = [
41
60
  // a harvest instruction through whenever it omitted an injection phrase.
42
61
  const SECRET_PATTERNS = [
43
62
  {
44
- re: /\b(?:read|extract|retrieve|fetch|obtain|dump|reveal|collect|harvest|grab|copy|print)\s[\s\S]{0,30}?\b(?:api[_\s-]?key|access[_\s-]?token|bearer\s+token|credential|password|passwd|secret|\.env\b|environment\s+variable)/i,
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,
45
67
  code: "TOOL_DEF_SECRET_HARVEST",
46
68
  severity: "critical",
47
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"],
48
77
  },
49
- { re: /\bprivate[_\s-]?key\b/i, code: "TOOL_DEF_SECRET_REQUEST", severity: "critical", tier: "block" },
50
- { re: /\bseed[_\s-]?phrase\b|\bmnemonic\b/i, code: "TOOL_DEF_SECRET_REQUEST", severity: "critical", tier: "block" },
51
- { re: /~\/\.ssh|\bid_rsa\b|\.ssh\/[\w.-]+/i, code: "TOOL_DEF_SECRET_REQUEST", severity: "critical", tier: "block" },
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"] },
52
86
  // Advisory: these are ordinary parameter names and ordinary setup prose.
53
- { re: /\bapi[_\s-]?key\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "low", tier: "advise" },
54
- { re: /\bcredentials?\b|\baccess[_\s-]?token\b|\bbearer\s+token\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "low", tier: "advise" },
55
- { re: /\bsecret(?:s)?\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "low", tier: "advise" },
56
- { re: /\bpassword\b|\bpasswd\b/i, code: "TOOL_DEF_CREDENTIAL_PARAM", severity: "medium", tier: "advise" },
57
- { re: /(?:^|[^.\w])\.env\b|\benvironment\s+variables?\b/i, code: "TOOL_DEF_ENV_REFERENCE", severity: "medium", tier: "advise" },
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 },
58
92
  ];
59
93
  // Dangerous URL schemes embedded in text.
60
94
  const URL_SCHEME_PATTERNS = [
61
- { re: /\bdata:[\w/+.-]+;base64,/i, code: "TOOL_DEF_DATA_URL", severity: "high", tier: "block" },
62
- { re: /\bjavascript:/i, code: "TOOL_DEF_DATA_URL", severity: "high", tier: "block" },
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"] },
63
102
  ];
64
103
  // Hidden payloads. Part of the rule table (and therefore the digest) rather than
65
104
  // special cases in the scan loop.
@@ -71,7 +110,9 @@ const PAYLOAD_PATTERNS = [
71
110
  code: "TOOL_DEF_BASE64_BLOB",
72
111
  severity: "high",
73
112
  tier: "block",
113
+ surfaces: ALL_SURFACES,
74
114
  note: "contains a long base64-encoded blob — possible hidden payload",
115
+ guards: ["blob"],
75
116
  },
76
117
  {
77
118
  // U+200B–200F, U+202A–202E, U+2060, U+FEFF. Built from a \u-escaped string so
@@ -80,9 +121,235 @@ const PAYLOAD_PATTERNS = [
80
121
  code: "TOOL_DEF_HIDDEN_UNICODE",
81
122
  severity: "high",
82
123
  tier: "block",
124
+ surfaces: ALL_SURFACES,
83
125
  note: "contains zero-width or bidi control characters hiding text from review",
126
+ guards: ["zeroWidth"],
84
127
  },
85
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;
86
353
  const RULES = [
87
354
  ...INJECTION_PATTERNS,
88
355
  ...EXFIL_PATTERNS,
@@ -98,8 +365,21 @@ const RULES = [
98
365
  * 2 — block/advise tiers; exfil "send … to" anchored on an external destination;
99
366
  * TOOL_DEF_SECRET_HARVEST added so demoting the credential nouns does not
100
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.
101
381
  */
102
- export const STATIC_SCAN_RULESET_VERSION = "2";
382
+ export const STATIC_SCAN_RULESET_VERSION = "4";
103
383
  const SEVERITY_RANK = {
104
384
  info: 0,
105
385
  low: 1,
@@ -132,8 +412,10 @@ export function staticScanRuleset() {
132
412
  code: r.code,
133
413
  severity: r.severity,
134
414
  tier: r.tier,
415
+ surfaces: [...r.surfaces],
135
416
  source: r.re.source,
136
417
  flags: r.re.flags,
418
+ guards: [...(r.guards ?? [])],
137
419
  })).sort((a, b) => cmp(a.code, b.code) || cmp(a.source, b.source) || cmp(a.flags, b.flags));
138
420
  const preimage = canonicalize({ version: STATIC_SCAN_RULESET_VERSION, rules });
139
421
  const digest = `sha256-${createHash("sha256").update(preimage, "utf8").digest("base64")}`;
@@ -150,26 +432,55 @@ export function staticScanRulesetRef() {
150
432
  }
151
433
  export class StaticScanGate {
152
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
+ }
153
444
  async evaluate(input) {
154
445
  const findings = [];
155
446
  for (const tool of input.tools) {
156
447
  const schemaText = safeStringifySchema(tool.inputSchema);
157
- // Description is prose; schema text is field names + descriptions + enums.
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).
158
451
  const haystacks = [
159
- { text: tool.description ?? "", where: "description" },
160
- { text: schemaText, where: "input schema" },
452
+ { text: tool.name ?? "", surface: "name", where: "name" },
453
+ { text: tool.description ?? "", surface: "description", where: "description" },
454
+ { text: schemaText, surface: "inputSchema", where: "input schema" },
161
455
  ];
162
- for (const { text, where } of haystacks) {
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) {
163
461
  for (const rule of RULES) {
164
- if (!rule.re.test(text))
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}`);
165
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);
166
477
  const finding = {
167
478
  gate: this.name,
168
479
  severity: rule.severity,
169
480
  code: rule.code,
170
481
  message: rule.note
171
- ? `Tool "${tool.name}" ${where} ${rule.note}.`
172
- : `Tool "${tool.name}" ${where} matches ${rule.code} signature (${describe(rule.re)}).`,
482
+ ? `Tool "${shown}" ${where} ${rule.note} — at "${span}".`
483
+ : `Tool "${shown}" ${where} matches ${rule.code} signature (${describe(rule.re)}) at "${span}".`,
173
484
  tool: tool.name,
174
485
  };
175
486
  if (rule.tier === "advise")
@@ -212,4 +523,17 @@ function safeStringifySchema(schema) {
212
523
  function describe(re) {
213
524
  return re.source.length > 48 ? `${re.source.slice(0, 45)}…` : re.source;
214
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
+ }
215
539
  //# sourceMappingURL=static-scan.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"static-scan.js","sourceRoot":"","sources":["../src/static-scan.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"static-scan.js","sourceRoot":"","sources":["../src/static-scan.ts"],"names":[],"mappings":"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"}
@@ -66,6 +66,7 @@ export interface ThreatFeedOptions {
66
66
  }
67
67
  export declare class ThreatFeed {
68
68
  private records;
69
+ private compiled;
69
70
  private feedPublicKey?;
70
71
  private readonly maxAgeMs;
71
72
  private readonly now;
@@ -74,6 +75,8 @@ export declare class ThreatFeed {
74
75
  /** The built-in floor, always present regardless of remote load state. */
75
76
  get builtins(): ThreatRecord[];
76
77
  all(): ThreatRecord[];
78
+ /** Single place where the record set changes, so the match cache cannot go stale. */
79
+ private setRecords;
77
80
  /**
78
81
  * Fetch and verify a signed remote threat feed.
79
82
  *
@@ -1 +1 @@
1
- {"version":3,"file":"threat-feed.d.ts","sourceRoot":"","sources":["../src/threat-feed.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,YAAY,EAEZ,YAAY,EAEZ,OAAO,EACP,aAAa,EACb,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,QAAsB,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AA+GhD,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAe;gBAExB,IAAI,CAAC,EAAE,iBAAiB;IAUpC,0EAA0E;IAC1E,IAAI,QAAQ,IAAI,YAAY,EAAE,CAE7B;IAED,GAAG,IAAI,YAAY,EAAE;IAIrB;;;;;;;;;;;;;;;;;;OAkBG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAgH3C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,GAAE,OAAO,EAAO,GAAG,aAAa,EAAE;CA6CpE;AAED;;;;;;;;;GASG;AACH,qBAAa,UAAW,YAAW,UAAU;IAG/B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,QAAQ,CAAC,IAAI,iBAAiB;gBAED,IAAI,EAAE,UAAU;IAEvC,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAMlE"}
1
+ {"version":3,"file":"threat-feed.d.ts","sourceRoot":"","sources":["../src/threat-feed.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,YAAY,EAEZ,YAAY,EAEZ,OAAO,EACP,aAAa,EACb,UAAU,EACV,eAAe,EACf,gBAAgB,EAChB,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,uBAAuB,QAAsB,CAAC;AAE3D;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,QAAgB,CAAC;AA2HhD,MAAM,WAAW,iBAAiB;IAChC,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAcD,qBAAa,UAAU;IACrB,OAAO,CAAC,OAAO,CAAgC;IAC/C,OAAO,CAAC,QAAQ,CAA2C;IAC3D,OAAO,CAAC,aAAa,CAAC,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAe;gBAExB,IAAI,CAAC,EAAE,iBAAiB;IAUpC,0EAA0E;IAC1E,IAAI,QAAQ,IAAI,YAAY,EAAE,CAE7B;IAED,GAAG,IAAI,YAAY,EAAE;IAIrB,qFAAqF;IACrF,OAAO,CAAC,UAAU;IAKlB;;;;;;;;;;;;;;;;;;OAkBG;IACG,IAAI,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA8I3C;;;;;;;;;;;;;;;;;;;OAmBG;IACH,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,KAAK,GAAE,OAAO,EAAO,GAAG,aAAa,EAAE;CAmDpE;AAED;;;;;;;;;GASG;AACH,qBAAa,UAAW,YAAW,UAAU;IAG/B,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,QAAQ,CAAC,IAAI,iBAAiB;gBAED,IAAI,EAAE,UAAU;IAEvC,QAAQ,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAMlE"}