agent-sanitizer 2.27.0 → 2.28.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -35,6 +35,10 @@ const { cleaned, found, warnings, notes } = await sanitize(untrustedText);
35
35
 
36
36
  // Opt into the HTML layers for web ingress (lazy-loads ~200 ms of deps):
37
37
  const result = await sanitize(pageSource, { html: true });
38
+
39
+ // Layer 3 alone: flag exfil-shaped URLs without splicing anything (for text
40
+ // that must stay byte-faithful, e.g. a PR diff). Implied by `html: true`.
41
+ const scanned = await sanitize(diffText, { exfilScan: true });
38
42
  ```
39
43
 
40
44
  `sanitize` never throws and never silently drops content—any change comes with
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-sanitizer",
3
- "version": "2.27.0",
3
+ "version": "2.28.0",
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": {
package/src/index.mjs CHANGED
@@ -87,20 +87,26 @@ export {
87
87
  * to the four fields this entry promises — `modified`/`sgrNote`
88
88
  * describe the tool-output pipeline's banner, and `reveal` is produced only by
89
89
  * options this facade does not expose. `html` selects Layers 2 AND 3 together
90
- * here, which is the surface this entry has always had; `sanitizeText` takes
91
- * them as separate flags for the tool-output pipeline, which needs Layer 3's
92
- * detection without Layer 2's splice.
90
+ * here, which is the surface this entry has always had; `exfilScan` exposes
91
+ * Layer 3's non-destructive detection on its own (unconditionally implied by
92
+ * `html`, which it can add to but never switch off) for
93
+ * callers that must keep the visible bytes intact — e.g. a PR diff where the
94
+ * Layer-2 splice would corrupt legitimate markup — matching the separate
95
+ * flags `sanitizeText` takes for the tool-output pipeline.
93
96
  * @param {string} text
94
- * @param {{ html?: boolean } | null} [options]
97
+ * @param {{ html?: boolean, exfilScan?: boolean } | null} [options]
95
98
  * @returns {Promise<{ cleaned: string, found: string[], warnings: string[], notes: string[] }>}
96
99
  */
97
100
  export async function sanitize(text, options) {
98
101
  if (typeof text !== "string")
99
102
  throw new TypeError("sanitize(text, options): text must be a string");
100
- const { html = false } = options ?? {};
103
+ const { html = false, exfilScan = false } = options ?? {};
101
104
  const { cleaned, found, warnings, notes } = await sanitizeText(text, {
102
105
  html,
103
- exfilScan: html,
106
+ // `html` implies the scan unconditionally, and `exfilScan` can only ADD it:
107
+ // an opt-OUT would make `{ html: true, exfilScan: false }` splice Layer 2
108
+ // while silently dropping Layer 3's report — a fail-open the docs deny.
109
+ exfilScan: exfilScan || html,
104
110
  });
105
111
  return { cleaned, found, warnings, notes };
106
112
  }
package/types/index.d.mts CHANGED
@@ -24,15 +24,19 @@
24
24
  * to the four fields this entry promises — `modified`/`sgrNote`
25
25
  * describe the tool-output pipeline's banner, and `reveal` is produced only by
26
26
  * options this facade does not expose. `html` selects Layers 2 AND 3 together
27
- * here, which is the surface this entry has always had; `sanitizeText` takes
28
- * them as separate flags for the tool-output pipeline, which needs Layer 3's
29
- * detection without Layer 2's splice.
27
+ * here, which is the surface this entry has always had; `exfilScan` exposes
28
+ * Layer 3's non-destructive detection on its own (unconditionally implied by
29
+ * `html`, which it can add to but never switch off) for
30
+ * callers that must keep the visible bytes intact — e.g. a PR diff where the
31
+ * Layer-2 splice would corrupt legitimate markup — matching the separate
32
+ * flags `sanitizeText` takes for the tool-output pipeline.
30
33
  * @param {string} text
31
- * @param {{ html?: boolean } | null} [options]
34
+ * @param {{ html?: boolean, exfilScan?: boolean } | null} [options]
32
35
  * @returns {Promise<{ cleaned: string, found: string[], warnings: string[], notes: string[] }>}
33
36
  */
34
37
  export function sanitize(text: string, options?: {
35
38
  html?: boolean;
39
+ exfilScan?: boolean;
36
40
  } | null): Promise<{
37
41
  cleaned: string;
38
42
  found: string[];