agent-sanitizer 2.2.1 → 2.2.2

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/package.json +1 -1
  2. package/src/rehydrate.mjs +21 -11
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-sanitizer",
3
- "version": "2.2.1",
3
+ "version": "2.2.2",
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/rehydrate.mjs CHANGED
@@ -183,21 +183,31 @@ async function rehydrateEdit(
183
183
  // (the model supplied the secret's real bytes itself, e.g. a rotation)
184
184
  // extracts nothing and is left to the literal resolver below.
185
185
  const diskSpans = pairDiskSpans(view, deletions);
186
- const intrudes = occurrences(content, oldS).some((matchStart) => {
186
+ let intrusion = null;
187
+ for (const matchStart of occurrences(content, oldS)) {
187
188
  const matchEnd = matchStart + oldS.length;
188
- return diskSpans.some(
189
- (secret) =>
190
- matchStart < secret.end &&
191
- secret.start < matchEnd &&
192
- !(matchStart <= secret.start && secret.end <= matchEnd),
189
+ const secret = diskSpans.find(
190
+ (span) =>
191
+ matchStart < span.end &&
192
+ span.start < matchEnd &&
193
+ !(matchStart <= span.start && span.end <= matchEnd),
193
194
  );
194
- });
195
- if (intrudes)
195
+ if (secret) {
196
+ intrusion = { matchStart, matchEnd, secret };
197
+ break;
198
+ }
199
+ }
200
+ // Report both byte ranges. The refusal is conservative — it fires on an
201
+ // overlap with the redacted span the caller cannot see — so the caller
202
+ // needs the ranges to tell a true overlap from a mis-sized redaction.
203
+ if (intrusion)
196
204
  return {
197
205
  deny:
198
- `old_string matches bytes inside a ${hint}…] redacted secret in ` +
199
- `${ti.file_path} that are hidden from your view; edit only text you can ` +
200
- `see (include each placeholder whole), or ask the user to make this change`,
206
+ `old_string does not appear in the sanitized view of ${ti.file_path}; on disk ` +
207
+ `it matches bytes ${intrusion.matchStart}-${intrusion.matchEnd}, which fall ` +
208
+ `inside a ${hint}…] redacted secret at bytes ${intrusion.secret.start}-` +
209
+ `${intrusion.secret.end} that are hidden from your view; edit only text you ` +
210
+ `can see (include each placeholder whole), or ask the user to make this change`,
201
211
  };
202
212
  const literalRes = rehydrateNewString(
203
213
  oldS,