feat(injection): E3 — rot13 layer for comment-block injection
Adds rot13 to the variantSet built in scanForInjection(), so imperative phrases hidden as rot13 inside code comments still hit the existing CRITICAL/HIGH/MEDIUM pattern arrays. normalizeForScan() already covers base64, hex, URL, and HTML decoding in a 3-iteration loop — those are NOT duplicated here. rot13 is the only genuinely new variant: it is its own inverse and not part of any NIST/Unicode normalization spec, so it has to be applied explicitly. Threshold: only inputs >40 chars enter the rot13 pass, to suppress false positives on accidental letter-shifts in tokens, ids, and short identifiers. Variants are deduplicated against the existing set so matchers do not run twice. 3 new tests in injection-patterns.test.mjs (rot13 detection, sub-40 char suppression, plaintext path still green). Total 168 tests pass. Closes E3 in critical-review-2026-04-20.md.
This commit is contained in:
parent
336e4db1b8
commit
950e4e4bce
3 changed files with 79 additions and 1 deletions
|
|
@ -6,7 +6,7 @@
|
|||
//
|
||||
// Zero external dependencies beyond ./string-utils.mjs.
|
||||
|
||||
import { normalizeForScan, containsUnicodeTags, decodeUnicodeTags, foldHomoglyphs } from './string-utils.mjs';
|
||||
import { normalizeForScan, containsUnicodeTags, decodeUnicodeTags, foldHomoglyphs, rot13 } from './string-utils.mjs';
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Critical patterns — direct injection attempts (should be blocked)
|
||||
|
|
@ -230,6 +230,23 @@ export function scanForInjection(text) {
|
|||
if (foldedNormalized !== text && foldedNormalized !== normalized && foldedNormalized !== folded) {
|
||||
variantSet.add(foldedNormalized);
|
||||
}
|
||||
|
||||
// E3 — rot13 layer for comment-block injection. Attackers occasionally
|
||||
// hide imperative phrases ("ignore previous instructions") in rot13
|
||||
// inside code comments to evade plain-text gates. Apply only to inputs
|
||||
// long enough to plausibly contain a meaningful sentence (>40 chars) —
|
||||
// shorter strings hit the rate of FP on accidental rot13-look-alikes.
|
||||
// base64/hex/URL/HTML decoding is already done by normalizeForScan;
|
||||
// this is the only genuinely new variant added here.
|
||||
if (text.length > 40) {
|
||||
const r1 = rot13(text);
|
||||
if (r1 !== text && !variantSet.has(r1)) variantSet.add(r1);
|
||||
if (normalized.length > 40) {
|
||||
const r2 = rot13(normalized);
|
||||
if (r2 !== normalized && !variantSet.has(r2)) variantSet.add(r2);
|
||||
}
|
||||
}
|
||||
|
||||
const variants = [...variantSet];
|
||||
|
||||
for (const variant of variants) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue