agent-sanitizer 2.40.1 → 2.40.3

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 (2) hide show
  1. package/THREAT-MODEL.md +42 -1
  2. package/package.json +1 -1
package/THREAT-MODEL.md CHANGED
@@ -183,7 +183,7 @@ normalizer so they cannot drift.
183
183
 
184
184
  **Detection.** detect-secrets is the single oracle — its bundled plugins plus
185
185
  gitleaks-sourced ones for formats it lacks — extended with a regex
186
- for the unquoted `key=value` shapes `KeywordDetector` misses, PEM block
186
+ for the unquoted `key=value` shapes the keyword detector misses, PEM block
187
187
  collapse, cross-line reassembly of a secret split across lines, and exact-match
188
188
  redaction of caller-supplied env-var **values**. Each hit becomes
189
189
  `[REDACTED: <label>]` and its label joins `found`.
@@ -676,3 +676,44 @@ is only as durable as the files carrying it.
676
676
  The knob adds no layer and changes no layer's semantics. Ambiguous input still
677
677
  fails open at the detection level (precision over recall), as it always has —
678
678
  that is a separate, and unrelated, sense of the phrase.
679
+
680
+ ## Benchmark (`test/injection-corpus.test.mjs`)
681
+
682
+ The published "invisible prompt injection" corpora fall in two families, and
683
+ only one benchmarks a deterministic transform. Model-susceptibility suites
684
+ (AgentDojo, InjecAgent, Agent Security Bench, LLMail-Inject, Reverse CAPTCHA)
685
+ measure whether a _model_ obeys an injection; scoring against them needs an LLM
686
+ in the loop, and most inject in plaintext — a channel this library does not
687
+ touch. Payload corpora do apply, because ground truth ("this text carries
688
+ operator-hidden content") is checkable with no model.
689
+
690
+ `test/injection-corpus.test.mjs` is that benchmark, built the way the rest of
691
+ this repo pins behavior: a self-authored, append-only corpus. It transcribes
692
+ each documented encoding — the encoders in the file are the cited spec, not a
693
+ vendored dependency — over benign carrier and payload text, and scores the pair
694
+ a sanitizer is actually responsible for: the concealment is **neutralized** and
695
+ the finding is **reported at the right tier**. One vector per named technique:
696
+
697
+ - Unicode tags (garak `goodside.Tag`; Cisco Unicode-tag advisory) → Layer 1.
698
+ - Zero-width binary (Reverse CAPTCHA) → Layer 1.
699
+ - Variation-selector smuggling (sneaky-bits; garak `badchars`) → Layer 1.
700
+ - ANSI hidden text (garak `ansiescape`) → Layer 1.
701
+ - Bidi override (Trojan Source; garak `badchars`) → Layer 1.
702
+ - Markdown-image exfil URL (garak `web_injection.MarkdownImageExfil`) → Layer 3.
703
+ - Homoglyph command (garak `smuggling.HomoglyphObfuscation`) → Layer 4.
704
+
705
+ Two things the corpus fixes that a naive harness gets wrong. It drives Layer 4
706
+ through the wired `namespace-guard` seam, not `sanitize()` — which never reaches
707
+ confusable folding, so a one-entry-point harness reports a false 0% on every
708
+ homoglyph vector. And it pins the _observed_ verdict, not a wished one: a short
709
+ bidi override is stripped and reported (`cf-format`) but is not payload-shaped,
710
+ so `classifyPrompt` passes it — recorded as a measured partial-coverage point
711
+ rather than asserted away.
712
+
713
+ The benign twin is load-bearing. Every public corpus is positives-only, and a
714
+ recall-only score rewards the over-triggering this repo forbids ("flag
715
+ everything" scores 100%). The corpus pairs the vectors with legitimate inputs —
716
+ preserved ZWNJ/ZWJ joiners, emoji sequences, non-Latin prose, long-but-benign
717
+ opaque-token URLs (presigned S3, OAuth callbacks) — asserting **zero** findings,
718
+ so the number that ships is precision alongside recall. `INJECTION_REPORT=1
719
+ node --test test/injection-corpus.test.mjs` prints the roll-up.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-sanitizer",
3
- "version": "2.40.1",
3
+ "version": "2.40.3",
4
4
  "description": "Defend an agent against hidden-content injection: strip payload-capable invisible Unicode and ANSI, splice out human-invisible HTML, and flag data-exfil URLs in untrusted text before any model sees it.",
5
5
  "type": "module",
6
6
  "repository": {