fix(#2873): write bidi codepoints as escapes, not literals

The invisible-Unicode scan flagged the compiled sanitizer: BIDI_RE in
install-shadow-report.cts carried literal U+202A-U+202E where its two
neighbouring regexes already used \u{...} escapes, so the module that
strips bidi controls was itself a carrier for them.

The prompt-injection-scan failure alongside it was the same defect rolling
up through the parent describe, not a second cause - verified by running
the scanner across every category it checks.

Test fixtures and property generators now name their codepoints (RLO, LRE,
PDI) instead of embedding invisible bytes, so a reviewer can see which
character is under test.

Refs #2873
This commit is contained in:
sim
2026-08-15 00:02:37 -04:00
parent 2d72577e07
commit d37e594ec8
3 changed files with 23 additions and 5 deletions

View File

@@ -80,6 +80,12 @@ function declaredRuntimeReport(runtimeVal) {
return buildShadowReport('claude', baseOpts(home, cwd, { readManifest: mkReadManifest(byConfigHome) }));
}
// RLO (Right-to-Left Override, U+202E) — written as a `\u{...}` escape (not
// a literal bidi character) so the source stays plain ASCII and does not
// carry the very invisible/dangerous-Unicode class it tests. See the
// matching B17/B18 note further below for the same rationale.
const BIDI_RLO = '\u{202E}';
// ─── B1-B4 — hostile declaredRuntime payloads are neutralized in the IR ────
describe('buildShadowReport — hostile declaredRuntime is sanitized in the IR (B1-B4)', () => {
@@ -109,7 +115,7 @@ describe('buildShadowReport — hostile declaredRuntime is sanitized in the IR (
});
test('bidi override is stripped (B4)', () => {
const report = declaredRuntimeReport('a‮b');
const report = declaredRuntimeReport(`a${BIDI_RLO}b`);
assert.strictEqual(report.mismatches[0].declaredRuntime, 'ab');
});
});