32 lines
1.3 KiB
TypeScript
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);
|
|
}
|