36 lines
2.2 KiB
Python
36 lines
2.2 KiB
Python
"""Muster für Inhalte, die wie Anweisungen an eine KI aussehen.
|
|
|
|
Die Liste ist bewusst klein und präzise: Ein Treffer blockiert nichts, er wird
|
|
protokolliert (Ereignis untrusted_signal, Metrik aiw_untrusted_signals_total) und
|
|
der Inhalt für das Modell gekennzeichnet. Neue Muster hier ergänzen und in
|
|
tests/injection_corpus.py ein Beispiel dazu aufnehmen.
|
|
"""
|
|
|
|
import re
|
|
|
|
W = r"\W+(?:\w+\W+){0,%d}" # bis zu n Wörter dazwischen
|
|
|
|
PATTERNS: tuple[tuple[str, re.Pattern[str]], ...] = tuple((name, re.compile(rx, re.IGNORECASE)) for name, rx in (
|
|
("ignore_instructions", r"\b(ignore|disregard|forget|override)" + W % 2 + r"(all|any|previous|prior|above|"
|
|
r"earlier|your|the)" + W % 2 + r"(instructions?|rules|prompts?|guidelines)\b"),
|
|
("ignoriere_anweisungen", r"\b(ignorier\w*|vergiss|vergesst|missachte\w*)" + W % 3 + r"(alle|vorherige\w*|"
|
|
r"bisherige\w*|obige\w*|deine|sämtliche)" + W % 2 + r"(anweisung\w*|regeln|"
|
|
r"vorgaben|instruktion\w*)"),
|
|
("rollenwechsel", r"\b(you are now|from now on,? you (are|will|must)|du bist (jetzt|ab sofort|nun) (ein|eine|"
|
|
r"der|die|kein)|ab (jetzt|sofort) bist du)\b"),
|
|
("systemnachricht", r"\b(new|updated|neuer?|geänderter?)\s+system\s?-?prompt\b|\[\s*system\s*\]|"
|
|
r"<\|?(system|im_start)\|?>|\bsystem override\b"),
|
|
("einfassung", r"</?\s*(fremdinhalt|projektregeln|arbeitsnotiz|plan_schritte)\b"),
|
|
("tool_aufruf", r"\b(call|invoke|run|use|execute|rufe|nutze|verwende|führe)" + W % 3 +
|
|
r"(commit_change|merge_target|update_plan)\b"),
|
|
("rechte_umgehen", r"\b(bypass\w*|umgeh\w*|skip)" + W % 2 + r"(approvals?|freigabe\w*|reviews?|policy|"
|
|
r"policies|richtlinie\w*)\b"),
|
|
("geheimnisse", r"\b(send|reveal|leak|exfiltrate|post|schick\w*|verrat\w*|sende\w*|übermittle\w*)" + W % 4 +
|
|
r"(api[ _-]?keys?|secrets?|passw(or)?[dt]s?|zugangsdaten|credentials)\b"),
|
|
))
|
|
|
|
|
|
def scan(text: str) -> list[str]:
|
|
"""Namen der Muster, die im Text vorkommen (höchstens die ersten 200 000 Zeichen)."""
|
|
sample = text[:200_000]
|
|
return [name for name, pattern in PATTERNS if pattern.search(sample)]
|