-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpatterns.py
More file actions
172 lines (159 loc) · 5.8 KB
/
Copy pathpatterns.py
File metadata and controls
172 lines (159 loc) · 5.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
"""Pattern definitions used by the scanner.
Every pattern belongs to a category and carries a severity weight. Patterns
are intentionally heuristic (regex + structural checks) rather than
ML-based: no model download, no network call, no GPU. That trade-off means
lower recall against novel phrasing, but the resulting scanner is trivial to
audit, runs in microseconds, and has zero supply-chain surface.
"""
from __future__ import annotations
import re
from dataclasses import dataclass
from enum import Enum
class Severity(Enum):
LOW = 5
MEDIUM = 12
HIGH = 25
CRITICAL = 55
@dataclass(frozen=True)
class Pattern:
name: str
category: str
severity: Severity
regex: re.Pattern
description: str
def _p(name: str, category: str, severity: Severity, pattern: str, description: str) -> Pattern:
return Pattern(
name=name,
category=category,
severity=severity,
regex=re.compile(pattern, re.IGNORECASE | re.MULTILINE),
description=description,
)
PATTERNS: list[Pattern] = [
# -- instruction override -------------------------------------------------
_p(
"override_ignore_previous",
"instruction_override",
Severity.CRITICAL,
r"\bignore\s+(?:all|any|the)?\s*(?:previous|prior|above|preceding|earlier)\s+"
r"(?:instructions?|prompts?|rules?|directives?|context)\b",
"Asks the model to disregard prior instructions.",
),
_p(
"override_disregard",
"instruction_override",
Severity.CRITICAL,
r"\bdisregard\s+(?:all|any|the)?\s*(?:previous|prior|above)\s+"
r"(?:instructions?|context|rules?|guidance)\b",
"Asks the model to disregard prior context.",
),
_p(
"override_forget",
"instruction_override",
Severity.HIGH,
r"\bforget\s+(?:everything|all)\s+(?:you\s+(?:were|have\s+been)\s+told|above|previous)\b",
"Asks the model to forget earlier guidance.",
),
_p(
"override_new_instructions",
"instruction_override",
Severity.HIGH,
r"\b(?:new|updated|real|actual)\s+instructions?\s*:",
"Introduces a competing instruction block.",
),
_p(
"override_arabic_ignore",
"instruction_override",
Severity.CRITICAL,
r"تجاهل\s*(?:كل|جميع)?\s*(?:التعليمات|الأوامر|التوجيهات)\s*(?:السابقة|أعلاه|الأولى)?",
"Arabic: asks the model to ignore previous instructions.",
),
_p(
"override_arabic_disregard",
"instruction_override",
Severity.HIGH,
r"انسَ\s*(?:كل|جميع)?\s*(?:ما سبق|التعليمات)",
"Arabic: asks the model to forget prior instructions.",
),
# -- role hijack ------------------------------------------------------------
_p(
"role_you_are_now",
"role_hijack",
Severity.HIGH,
r"\byou\s+are\s+now\s+(?:a|an|in)\s+\w+",
"Attempts to reassign the model's role or persona.",
),
_p(
"role_act_as",
"role_hijack",
Severity.MEDIUM,
r"\b(?:act\s+as|pretend\s+(?:you\s+are|to\s+be)|roleplay\s+as)\b",
"Attempts to reframe the model into a different persona.",
),
_p(
"role_developer_mode",
"role_hijack",
Severity.CRITICAL,
r"\b(?:developer\s+mode|dan\s+mode|jailbreak(?:ed)?|do\s+anything\s+now)\b",
"References known jailbreak personas/modes.",
),
_p(
"role_fake_system_marker",
"role_hijack",
Severity.CRITICAL,
r"(?:^|\n)\s*(?:system|admin|root|developer)\s*:\s",
"Fake role marker mimicking a privileged message.",
),
_p(
"role_chat_template_tokens",
"role_hijack",
Severity.CRITICAL,
r"<\|im_start\|>|<\|im_end\|>|\[INST\]|\[/INST\]|<<SYS>>|<</SYS>>",
"Raw chat-template control tokens embedded in content.",
),
# -- prompt / secret exfiltration -------------------------------------------
_p(
"exfil_send_data",
"exfiltration",
Severity.CRITICAL,
r"\b(?:send|post|upload|email|forward|leak)\s+(?:this|the\s+above|your|all|any)\s*"
r"(?:data|information|context|conversation|api\s*key|password|secret|credentials?)\b",
"Instructs the model to exfiltrate data to a third party.",
),
_p(
"exfil_markdown_image",
"exfiltration",
Severity.HIGH,
r"!\[[^\]]*\]\(\s*https?://[^\s)]+\)",
"Markdown image pointing at an external URL (classic exfil channel via auto-rendered images).",
),
_p(
"exfil_prompt_leak_request",
"prompt_leak",
Severity.MEDIUM,
r"\b(?:reveal|print|show|output|repeat)\s+(?:your|the)\s+"
r"(?:system\s+prompt|initial\s+prompt|instructions?)\b",
"Requests disclosure of the system prompt or hidden instructions.",
),
# -- hidden content -----------------------------------------------------------
_p(
"hidden_html_comment_instruction",
"hidden_content",
Severity.HIGH,
r"<!--.*?(?:ignore|instruction|system|prompt|assistant).*?-->",
"HTML comment carrying instruction-like text (invisible when rendered).",
),
_p(
"hidden_zero_width",
"hidden_content",
Severity.MEDIUM,
r"[]{2,}",
"Cluster of zero-width characters, often used to hide or split text from filters.",
),
]
# Unicode Tag block (U+E0000-U+E007F): invisible characters that can smuggle
# an entire hidden instruction string inside what looks like empty space.
# See: https://en.wikipedia.org/wiki/Tags_(Unicode_block)
TAG_BLOCK_RANGE = (0xE0000, 0xE007F)
# A run this long of base64 alphabet characters is unlikely to be prose.
BASE64_CANDIDATE = re.compile(r"(?:[A-Za-z0-9+/]{4}){16,}={0,2}")