import type { InjectionPattern, Finding, ScanResult } from '../types.js'; // Compiled at module load for performance (<20ms detection) export const INJECTION_PATTERNS: InjectionPattern[] = [ { name: 'Ignore instructions', pattern: /ignore\s+(all\s+)?(the\s+)?(previous|prior|above)\s+(instructions|prompts|rules)/i, severity: 'high', }, { name: 'New persona', pattern: /you\s+are\s+(now|no\s+longer)\s+/i, severity: 'high', }, { name: 'System prompt extraction', pattern: /(repeat|show|print|output|display)\s+(me\s+)?(your|the)\s+(system\s+)?(prompt|instructions|rules)/i, severity: 'high', }, { name: 'Jailbreak attempt', pattern: /\b(DAN|STAN|DUDE|AIM|UCAR)\b.*\b(mode|personality|character)\b/i, severity: 'high', }, { name: 'Forget instructions', pattern: /forget\s+(all\s+)?(your\s+)?(previous\s+)?(instructions|training|rules)/i, severity: 'high', }, { name: 'Role override', pattern: /from\s+now\s+on.*(?:you\s+(?:are|will|must|should)|act\s+as|pretend)/i, severity: 'medium', }, { name: 'Base64 command', pattern: /(?:decode|execute|run|eval)\s+(?:this\s+)?base64/i, severity: 'medium', }, { name: 'Hidden instruction marker', pattern: /\[INST\]|\[\/INST\]|<\|im_start\|>|<\|im_end\|>/i, severity: 'high', }, { name: 'XML injection', pattern: /|<\/system>||<\/assistant>/i, severity: 'high', }, ]; export const UNICODE_PATTERNS: InjectionPattern[] = [ { name: 'Zero-width chars', pattern: /[\u200B-\u200F\u202A-\u202E\uFEFF\u2060-\u2064]/, severity: 'high', }, { name: 'Right-to-left override', pattern: /[\u202D\u202E\u2066-\u2069]/, severity: 'medium', }, { name: 'Tag characters', pattern: /[\u{E0001}-\u{E007F}]/u, severity: 'high', }, ]; export function scanForInjection(text: string): ScanResult { const findings: Finding[] = []; for (const p of INJECTION_PATTERNS) { const match = p.pattern.exec(text); if (match) { findings.push({ rule: p.name, hook: 'prompt-injection-detector', severity: p.severity, matched: match[0].slice(0, 40) + (match[0].length > 40 ? '...' : ''), }); } } for (const p of UNICODE_PATTERNS) { const match = p.pattern.exec(text); if (match) { findings.push({ rule: p.name, hook: 'prompt-injection-detector', severity: p.severity, matched: `unicode char U+${match[0].codePointAt(0)?.toString(16).toUpperCase()}`, }); } } return { matched: findings.length > 0, findings }; }