agent-sanitizer 2.60.0 → 2.60.1
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.
|
@@ -27,15 +27,23 @@ import charset from "../../python/agent_sanitizer/data/invisible-charset.json" w
|
|
|
27
27
|
// every gap are what bound the match — a `*` gap is never adjacent to another
|
|
28
28
|
// gap, so there is no ambiguity to backtrack over and no ReDoS. (The class size
|
|
29
29
|
// is irrelevant to that: a character class matches in O(1) whether it holds one
|
|
30
|
-
// member or all 435.)
|
|
30
|
+
// member or all 435.) That argument holds only while no literal is itself a
|
|
31
|
+
// member of the class, so {@link envValueRegex} drops the value's own invisible
|
|
32
|
+
// code points before it splices: `a<ZWSP>a` would otherwise build
|
|
33
|
+
// `a[…]*<ZWSP>[…]*a`, whose two stars share the literal and backtrack
|
|
34
|
+
// quadratically over a long run of ZWSP.
|
|
35
|
+
const ENV_INVIS_CODEPOINTS = [
|
|
36
|
+
...new Set([...charset.cf_codepoints, ...charset.extra_codepoints]),
|
|
37
|
+
].sort((a, b) => a - b);
|
|
38
|
+
const ENV_INVIS_SET = new Set(ENV_INVIS_CODEPOINTS);
|
|
31
39
|
const ENV_INVIS_RUN =
|
|
32
40
|
"[" +
|
|
33
|
-
|
|
34
|
-
.sort((a, b) => a - b)
|
|
35
|
-
.map((cp) => `\\u{${cp.toString(16)}}`)
|
|
36
|
-
.join("") +
|
|
41
|
+
ENV_INVIS_CODEPOINTS.map((cp) => `\\u{${cp.toString(16)}}`).join("") +
|
|
37
42
|
"]*";
|
|
38
43
|
|
|
44
|
+
/** @param {string} ch */
|
|
45
|
+
const escapeLiteral = (ch) => ch.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
46
|
+
|
|
39
47
|
/**
|
|
40
48
|
* Regex matching `value` tolerating invisible chars spliced between its
|
|
41
49
|
* characters (mirrors the engine's env-value regex). Code-point split so
|
|
@@ -55,10 +63,15 @@ const ENV_INVIS_RUN =
|
|
|
55
63
|
export function envValueRegex(value) {
|
|
56
64
|
let re = ENV_VALUE_REGEX_CACHE.get(value);
|
|
57
65
|
if (re === undefined) {
|
|
66
|
+
const visible = [...value].filter(
|
|
67
|
+
(ch) => !ENV_INVIS_SET.has(/** @type {number} */ (ch.codePointAt(0))),
|
|
68
|
+
);
|
|
69
|
+
// A value made only of invisibles has no literal to anchor a gap on: match
|
|
70
|
+
// it exactly rather than build a pattern that is nothing but gaps.
|
|
58
71
|
re = new RegExp(
|
|
59
|
-
|
|
60
|
-
.map(
|
|
61
|
-
.join(
|
|
72
|
+
visible.length > 0
|
|
73
|
+
? visible.map(escapeLiteral).join(ENV_INVIS_RUN)
|
|
74
|
+
: [...value].map(escapeLiteral).join(""),
|
|
62
75
|
"u",
|
|
63
76
|
);
|
|
64
77
|
ENV_VALUE_REGEX_CACHE.set(value, re);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-sanitizer",
|
|
3
|
-
"version": "2.60.
|
|
3
|
+
"version": "2.60.1",
|
|
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": {
|