fable-agent/src/core/prompt-injection-safety.ts

32 lines
1.3 KiB
TypeScript

import { findHiddenUnicode } from "./unicode-safety.js";
export interface PromptInjectionFinding {
kind: "hidden-unicode" | "reversed-tag" | "fake-wrapper" | "role-spoof" | "instruction-smuggling";
index: number;
match: string;
}
const PATTERNS: Array<{ kind: PromptInjectionFinding["kind"]; re: RegExp }> = [
{ kind: "reversed-tag", re: />\/?(?:gnikniht|metsys|loot|ekovni|retemarap)(?::lm?tna)?</gi },
{ kind: "fake-wrapper", re: /<\/?(?:system|developer|assistant|tool|invoke|parameter|antml:thinking|thinking)\b[^>]*>/gi },
{ kind: "role-spoof", re: /\b(?:ignore|override|disregard)\s+(?:all\s+)?(?:previous|prior|system|developer)\s+instructions\b/gi },
{ kind: "instruction-smuggling", re: /\b(?:system\s+prompt|developer\s+message|hidden\s+instructions?|reveal\s+your\s+prompt|repeat\s+your\s+instructions)\b/gi },
];
export function findPromptInjection(text: string): PromptInjectionFinding[] {
const findings: PromptInjectionFinding[] = findHiddenUnicode(text).map((hit) => ({
kind: "hidden-unicode",
index: hit.index,
match: hit.codePoint,
}));
for (const { kind, re } of PATTERNS) {
re.lastIndex = 0;
for (const match of text.matchAll(re)) {
findings.push({ kind, index: match.index, match: match[0].slice(0, 80) });
}
}
return findings.sort((a, b) => a.index - b.index);
}