@weave_protocol/mund 0.1.13 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +131 -17
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +73 -8
- package/dist/index.js.map +1 -1
- package/dist/threat-intel-index.d.ts +8 -0
- package/dist/threat-intel-index.d.ts.map +1 -0
- package/dist/threat-intel-index.js +11 -0
- package/dist/threat-intel-index.js.map +1 -0
- package/dist/threat-intel-manager.d.ts +41 -0
- package/dist/threat-intel-manager.d.ts.map +1 -0
- package/dist/threat-intel-manager.js +812 -0
- package/dist/threat-intel-manager.js.map +1 -0
- package/dist/threat-intel-tools.d.ts +208 -0
- package/dist/threat-intel-tools.d.ts.map +1 -0
- package/dist/threat-intel-tools.js +194 -0
- package/dist/threat-intel-tools.js.map +1 -0
- package/dist/threat-intel-types.d.ts +172 -0
- package/dist/threat-intel-types.d.ts.map +1 -0
- package/dist/threat-intel-types.js +6 -0
- package/dist/threat-intel-types.js.map +1 -0
- package/package.json +3 -3
- package/src/index.ts +99 -8
- package/src/threat-intel-index.ts +13 -0
- package/src/threat-intel-manager.ts +920 -0
- package/src/threat-intel-tools.ts +233 -0
- package/src/threat-intel-types.ts +233 -0
|
@@ -0,0 +1,812 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Threat Intelligence Manager
|
|
3
|
+
* @weave_protocol/mund
|
|
4
|
+
*/
|
|
5
|
+
// ============================================================================
|
|
6
|
+
// Built-in Threat Patterns
|
|
7
|
+
// ============================================================================
|
|
8
|
+
const BUILTIN_PATTERNS = [
|
|
9
|
+
// Prompt Injection patterns
|
|
10
|
+
{
|
|
11
|
+
id: 'pi_direct_override',
|
|
12
|
+
sourceId: 'weave_builtin',
|
|
13
|
+
category: 'prompt_injection',
|
|
14
|
+
name: 'Direct Instruction Override',
|
|
15
|
+
description: 'Attempts to directly override previous instructions',
|
|
16
|
+
patternType: 'regex',
|
|
17
|
+
pattern: 'ignore\\s+(all\\s+)?(previous|prior|above|earlier)\\s+(instructions|prompts|context)',
|
|
18
|
+
severity: 'critical',
|
|
19
|
+
confidence: 0.95,
|
|
20
|
+
mitreId: 'T1059',
|
|
21
|
+
mitreTactic: 'Execution',
|
|
22
|
+
mitreTechnique: 'Command and Scripting Interpreter',
|
|
23
|
+
tags: ['injection', 'override'],
|
|
24
|
+
enabled: true,
|
|
25
|
+
version: '1.0.0',
|
|
26
|
+
createdAt: new Date(),
|
|
27
|
+
updatedAt: new Date(),
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
id: 'pi_role_reassignment',
|
|
31
|
+
sourceId: 'weave_builtin',
|
|
32
|
+
category: 'prompt_injection',
|
|
33
|
+
name: 'Role Reassignment Attack',
|
|
34
|
+
description: 'Attempts to reassign the AI role',
|
|
35
|
+
patternType: 'regex',
|
|
36
|
+
pattern: 'you\\s+are\\s+(now|actually|really)\\s+(a|an|the)\\s+\\w+',
|
|
37
|
+
severity: 'critical',
|
|
38
|
+
confidence: 0.9,
|
|
39
|
+
mitreId: 'T1078',
|
|
40
|
+
mitreTactic: 'Defense Evasion',
|
|
41
|
+
mitreTechnique: 'Valid Accounts',
|
|
42
|
+
tags: ['injection', 'role'],
|
|
43
|
+
enabled: true,
|
|
44
|
+
version: '1.0.0',
|
|
45
|
+
createdAt: new Date(),
|
|
46
|
+
updatedAt: new Date(),
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
id: 'pi_delimiter_injection',
|
|
50
|
+
sourceId: 'weave_builtin',
|
|
51
|
+
category: 'prompt_injection',
|
|
52
|
+
name: 'Delimiter Injection',
|
|
53
|
+
description: 'Uses code blocks to inject system-level commands',
|
|
54
|
+
patternType: 'regex',
|
|
55
|
+
pattern: '```\\s*(system|admin|root|sudo)',
|
|
56
|
+
severity: 'high',
|
|
57
|
+
confidence: 0.85,
|
|
58
|
+
mitreId: 'T1055',
|
|
59
|
+
mitreTactic: 'Defense Evasion',
|
|
60
|
+
mitreTechnique: 'Process Injection',
|
|
61
|
+
tags: ['injection', 'delimiter'],
|
|
62
|
+
enabled: true,
|
|
63
|
+
version: '1.0.0',
|
|
64
|
+
createdAt: new Date(),
|
|
65
|
+
updatedAt: new Date(),
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
id: 'pi_encoded_payload',
|
|
69
|
+
sourceId: 'weave_builtin',
|
|
70
|
+
category: 'prompt_injection',
|
|
71
|
+
name: 'Encoded Payload Detection',
|
|
72
|
+
description: 'Detects base64 encoded payloads that may contain instructions',
|
|
73
|
+
patternType: 'regex',
|
|
74
|
+
pattern: 'base64[:\\s]+[A-Za-z0-9+/=]{50,}',
|
|
75
|
+
severity: 'high',
|
|
76
|
+
confidence: 0.8,
|
|
77
|
+
mitreId: 'T1027',
|
|
78
|
+
mitreTactic: 'Defense Evasion',
|
|
79
|
+
mitreTechnique: 'Obfuscated Files or Information',
|
|
80
|
+
tags: ['injection', 'encoding'],
|
|
81
|
+
enabled: true,
|
|
82
|
+
version: '1.0.0',
|
|
83
|
+
createdAt: new Date(),
|
|
84
|
+
updatedAt: new Date(),
|
|
85
|
+
},
|
|
86
|
+
// Jailbreak patterns
|
|
87
|
+
{
|
|
88
|
+
id: 'jb_dan',
|
|
89
|
+
sourceId: 'weave_builtin',
|
|
90
|
+
category: 'jailbreak',
|
|
91
|
+
name: 'DAN Jailbreak',
|
|
92
|
+
description: 'Do Anything Now jailbreak attempt',
|
|
93
|
+
patternType: 'regex',
|
|
94
|
+
pattern: '\\b(DAN|Do\\s+Anything\\s+Now)\\b',
|
|
95
|
+
severity: 'critical',
|
|
96
|
+
confidence: 0.95,
|
|
97
|
+
mitreId: 'T1548',
|
|
98
|
+
mitreTactic: 'Privilege Escalation',
|
|
99
|
+
mitreTechnique: 'Abuse Elevation Control Mechanism',
|
|
100
|
+
tags: ['jailbreak', 'dan'],
|
|
101
|
+
enabled: true,
|
|
102
|
+
version: '1.0.0',
|
|
103
|
+
createdAt: new Date(),
|
|
104
|
+
updatedAt: new Date(),
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
id: 'jb_developer_mode',
|
|
108
|
+
sourceId: 'weave_builtin',
|
|
109
|
+
category: 'jailbreak',
|
|
110
|
+
name: 'Developer Mode Exploit',
|
|
111
|
+
description: 'Attempts to enable developer or debug mode',
|
|
112
|
+
patternType: 'regex',
|
|
113
|
+
pattern: 'enable\\s+(developer|debug|admin|root)\\s+mode',
|
|
114
|
+
severity: 'critical',
|
|
115
|
+
confidence: 0.9,
|
|
116
|
+
mitreId: 'T1548',
|
|
117
|
+
mitreTactic: 'Privilege Escalation',
|
|
118
|
+
mitreTechnique: 'Abuse Elevation Control Mechanism',
|
|
119
|
+
tags: ['jailbreak', 'developer'],
|
|
120
|
+
enabled: true,
|
|
121
|
+
version: '1.0.0',
|
|
122
|
+
createdAt: new Date(),
|
|
123
|
+
updatedAt: new Date(),
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'jb_hypothetical',
|
|
127
|
+
sourceId: 'weave_builtin',
|
|
128
|
+
category: 'jailbreak',
|
|
129
|
+
name: 'Hypothetical Framing',
|
|
130
|
+
description: 'Uses hypothetical scenarios to bypass restrictions',
|
|
131
|
+
patternType: 'regex',
|
|
132
|
+
pattern: 'hypothetically|in\\s+theory|imagine\\s+if|pretend\\s+(that\\s+)?you',
|
|
133
|
+
severity: 'medium',
|
|
134
|
+
confidence: 0.7,
|
|
135
|
+
tags: ['jailbreak', 'hypothetical'],
|
|
136
|
+
enabled: true,
|
|
137
|
+
version: '1.0.0',
|
|
138
|
+
createdAt: new Date(),
|
|
139
|
+
updatedAt: new Date(),
|
|
140
|
+
},
|
|
141
|
+
// System Prompt Leak patterns
|
|
142
|
+
{
|
|
143
|
+
id: 'spl_direct_request',
|
|
144
|
+
sourceId: 'weave_builtin',
|
|
145
|
+
category: 'system_prompt_leak',
|
|
146
|
+
name: 'Direct System Prompt Request',
|
|
147
|
+
description: 'Direct request to reveal system prompt',
|
|
148
|
+
patternType: 'regex',
|
|
149
|
+
pattern: '(?:show|reveal|display|print|output|tell\\s+me)\\s+(?:your\\s+)?(?:system\\s+)?(?:prompt|instructions|rules)',
|
|
150
|
+
severity: 'high',
|
|
151
|
+
confidence: 0.9,
|
|
152
|
+
mitreId: 'T1082',
|
|
153
|
+
mitreTactic: 'Discovery',
|
|
154
|
+
mitreTechnique: 'System Information Discovery',
|
|
155
|
+
tags: ['leak', 'system_prompt'],
|
|
156
|
+
enabled: true,
|
|
157
|
+
version: '1.0.0',
|
|
158
|
+
createdAt: new Date(),
|
|
159
|
+
updatedAt: new Date(),
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
id: 'spl_indirect_extraction',
|
|
163
|
+
sourceId: 'weave_builtin',
|
|
164
|
+
category: 'system_prompt_leak',
|
|
165
|
+
name: 'Indirect System Prompt Extraction',
|
|
166
|
+
description: 'Indirect attempts to extract system prompt',
|
|
167
|
+
patternType: 'regex',
|
|
168
|
+
pattern: 'what\\s+(?:were\\s+you|are\\s+you)\\s+(?:told|instructed|programmed)\\s+to',
|
|
169
|
+
severity: 'medium',
|
|
170
|
+
confidence: 0.75,
|
|
171
|
+
mitreId: 'T1082',
|
|
172
|
+
mitreTactic: 'Discovery',
|
|
173
|
+
mitreTechnique: 'System Information Discovery',
|
|
174
|
+
tags: ['leak', 'extraction'],
|
|
175
|
+
enabled: true,
|
|
176
|
+
version: '1.0.0',
|
|
177
|
+
createdAt: new Date(),
|
|
178
|
+
updatedAt: new Date(),
|
|
179
|
+
},
|
|
180
|
+
// Data Exfiltration patterns
|
|
181
|
+
{
|
|
182
|
+
id: 'exfil_markdown_image',
|
|
183
|
+
sourceId: 'weave_builtin',
|
|
184
|
+
category: 'data_exfiltration',
|
|
185
|
+
name: 'Markdown Image Exfiltration',
|
|
186
|
+
description: 'Uses markdown images to exfiltrate data via URL parameters',
|
|
187
|
+
patternType: 'regex',
|
|
188
|
+
pattern: '!\\[.*?\\]\\(https?:\\/\\/[^\\s)]+\\?[^)]*(?:data|token|key|secret|password|auth)',
|
|
189
|
+
severity: 'critical',
|
|
190
|
+
confidence: 0.95,
|
|
191
|
+
mitreId: 'T1041',
|
|
192
|
+
mitreTactic: 'Exfiltration',
|
|
193
|
+
mitreTechnique: 'Exfiltration Over C2 Channel',
|
|
194
|
+
tags: ['exfiltration', 'markdown'],
|
|
195
|
+
enabled: true,
|
|
196
|
+
version: '1.0.0',
|
|
197
|
+
createdAt: new Date(),
|
|
198
|
+
updatedAt: new Date(),
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: 'exfil_url_injection',
|
|
202
|
+
sourceId: 'weave_builtin',
|
|
203
|
+
category: 'data_exfiltration',
|
|
204
|
+
name: 'URL Data Injection',
|
|
205
|
+
description: 'Attempts to inject data into URLs for exfiltration',
|
|
206
|
+
patternType: 'regex',
|
|
207
|
+
pattern: '(?:fetch|curl|wget|request)\\s+.*https?:\\/\\/[^\\s]+\\?.*(?:=\\$|=\\{|=`)',
|
|
208
|
+
severity: 'high',
|
|
209
|
+
confidence: 0.85,
|
|
210
|
+
mitreId: 'T1041',
|
|
211
|
+
mitreTactic: 'Exfiltration',
|
|
212
|
+
mitreTechnique: 'Exfiltration Over C2 Channel',
|
|
213
|
+
tags: ['exfiltration', 'url'],
|
|
214
|
+
enabled: true,
|
|
215
|
+
version: '1.0.0',
|
|
216
|
+
createdAt: new Date(),
|
|
217
|
+
updatedAt: new Date(),
|
|
218
|
+
},
|
|
219
|
+
// PII Extraction patterns
|
|
220
|
+
{
|
|
221
|
+
id: 'pii_harvesting',
|
|
222
|
+
sourceId: 'weave_builtin',
|
|
223
|
+
category: 'pii_extraction',
|
|
224
|
+
name: 'PII Harvesting Request',
|
|
225
|
+
description: 'Attempts to harvest personally identifiable information',
|
|
226
|
+
patternType: 'regex',
|
|
227
|
+
pattern: '(?:list|show|give|tell)\\s+(?:me\\s+)?(?:all\\s+)?(?:the\\s+)?(?:users?|customers?|employees?|people).*(?:names?|emails?|phones?|addresses?|ssn|social\\s+security)',
|
|
228
|
+
severity: 'high',
|
|
229
|
+
confidence: 0.85,
|
|
230
|
+
mitreId: 'T1005',
|
|
231
|
+
mitreTactic: 'Collection',
|
|
232
|
+
mitreTechnique: 'Data from Local System',
|
|
233
|
+
tags: ['pii', 'harvesting'],
|
|
234
|
+
enabled: true,
|
|
235
|
+
version: '1.0.0',
|
|
236
|
+
createdAt: new Date(),
|
|
237
|
+
updatedAt: new Date(),
|
|
238
|
+
},
|
|
239
|
+
// MCP Exploit patterns
|
|
240
|
+
{
|
|
241
|
+
id: 'mcp_tool_abuse',
|
|
242
|
+
sourceId: 'weave_builtin',
|
|
243
|
+
category: 'mcp_exploit',
|
|
244
|
+
name: 'MCP Tool Abuse',
|
|
245
|
+
description: 'Attempts to abuse MCP tools maliciously',
|
|
246
|
+
patternType: 'regex',
|
|
247
|
+
pattern: '(?:call|invoke|execute|run)\\s+(?:the\\s+)?(?:tool|function|mcp)\\s+.*(?:with|using)\\s+(?:malicious|dangerous|harmful)',
|
|
248
|
+
severity: 'critical',
|
|
249
|
+
confidence: 0.9,
|
|
250
|
+
mitreId: 'T1059',
|
|
251
|
+
mitreTactic: 'Execution',
|
|
252
|
+
mitreTechnique: 'Command and Scripting Interpreter',
|
|
253
|
+
tags: ['mcp', 'abuse'],
|
|
254
|
+
enabled: true,
|
|
255
|
+
version: '1.0.0',
|
|
256
|
+
createdAt: new Date(),
|
|
257
|
+
updatedAt: new Date(),
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: 'mcp_cross_tool',
|
|
261
|
+
sourceId: 'weave_builtin',
|
|
262
|
+
category: 'mcp_exploit',
|
|
263
|
+
name: 'Cross-Tool Attack',
|
|
264
|
+
description: 'Chains tool outputs to perform unauthorized actions',
|
|
265
|
+
patternType: 'regex',
|
|
266
|
+
pattern: '(?:use|call)\\s+(?:tool\\s+)?(?:output|result)\\s+(?:from|of)\\s+\\w+\\s+(?:as|for)\\s+(?:input|argument)\\s+(?:to|for)\\s+\\w+',
|
|
267
|
+
severity: 'high',
|
|
268
|
+
confidence: 0.8,
|
|
269
|
+
mitreId: 'T1055',
|
|
270
|
+
mitreTactic: 'Defense Evasion',
|
|
271
|
+
mitreTechnique: 'Process Injection',
|
|
272
|
+
tags: ['mcp', 'chain'],
|
|
273
|
+
enabled: true,
|
|
274
|
+
version: '1.0.0',
|
|
275
|
+
createdAt: new Date(),
|
|
276
|
+
updatedAt: new Date(),
|
|
277
|
+
},
|
|
278
|
+
// DoS patterns
|
|
279
|
+
{
|
|
280
|
+
id: 'dos_infinite_loop',
|
|
281
|
+
sourceId: 'weave_builtin',
|
|
282
|
+
category: 'dos_attack',
|
|
283
|
+
name: 'Infinite Loop Trigger',
|
|
284
|
+
description: 'Attempts to trigger infinite loops',
|
|
285
|
+
patternType: 'regex',
|
|
286
|
+
pattern: '(?:repeat|loop|continue)\\s+(?:this\\s+)?(?:forever|infinitely|until\\s+I\\s+say\\s+stop)',
|
|
287
|
+
severity: 'high',
|
|
288
|
+
confidence: 0.9,
|
|
289
|
+
mitreId: 'T1499',
|
|
290
|
+
mitreTactic: 'Impact',
|
|
291
|
+
mitreTechnique: 'Endpoint Denial of Service',
|
|
292
|
+
tags: ['dos', 'loop'],
|
|
293
|
+
enabled: true,
|
|
294
|
+
version: '1.0.0',
|
|
295
|
+
createdAt: new Date(),
|
|
296
|
+
updatedAt: new Date(),
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
id: 'dos_token_exhaustion',
|
|
300
|
+
sourceId: 'weave_builtin',
|
|
301
|
+
category: 'dos_attack',
|
|
302
|
+
name: 'Token Exhaustion',
|
|
303
|
+
description: 'Attempts to exhaust token limits',
|
|
304
|
+
patternType: 'regex',
|
|
305
|
+
pattern: '(?:generate|create|write)\\s+(?:a\\s+)?(?:very\\s+)?(?:long|huge|massive|enormous)\\s+(?:response|output|text)',
|
|
306
|
+
severity: 'medium',
|
|
307
|
+
confidence: 0.75,
|
|
308
|
+
mitreId: 'T1499',
|
|
309
|
+
mitreTactic: 'Impact',
|
|
310
|
+
mitreTechnique: 'Endpoint Denial of Service',
|
|
311
|
+
tags: ['dos', 'token'],
|
|
312
|
+
enabled: true,
|
|
313
|
+
version: '1.0.0',
|
|
314
|
+
createdAt: new Date(),
|
|
315
|
+
updatedAt: new Date(),
|
|
316
|
+
},
|
|
317
|
+
];
|
|
318
|
+
// ============================================================================
|
|
319
|
+
// Default Intel Sources
|
|
320
|
+
// ============================================================================
|
|
321
|
+
const DEFAULT_SOURCES = [
|
|
322
|
+
{
|
|
323
|
+
id: 'weave_builtin',
|
|
324
|
+
name: 'Weave Built-in Patterns',
|
|
325
|
+
type: 'weave_official',
|
|
326
|
+
description: 'Core threat patterns maintained by Weave Protocol',
|
|
327
|
+
enabled: true,
|
|
328
|
+
autoUpdate: false,
|
|
329
|
+
updateIntervalHours: 0,
|
|
330
|
+
patternCount: BUILTIN_PATTERNS.length,
|
|
331
|
+
version: '1.0.0',
|
|
332
|
+
categories: ['prompt_injection', 'jailbreak', 'data_exfiltration', 'system_prompt_leak', 'pii_extraction', 'mcp_exploit', 'dos_attack'],
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
id: 'weave_community',
|
|
336
|
+
name: 'Weave Community Blocklist',
|
|
337
|
+
type: 'community_blocklist',
|
|
338
|
+
url: 'https://raw.githubusercontent.com/Tyox-all/weave-intel/main/blocklist.json',
|
|
339
|
+
description: 'Community-contributed threat patterns',
|
|
340
|
+
enabled: true,
|
|
341
|
+
autoUpdate: true,
|
|
342
|
+
updateIntervalHours: 24,
|
|
343
|
+
patternCount: 0,
|
|
344
|
+
version: '0.0.0',
|
|
345
|
+
categories: [],
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
id: 'mitre_llm',
|
|
349
|
+
name: 'MITRE ATT&CK for LLMs',
|
|
350
|
+
type: 'mitre_attack',
|
|
351
|
+
url: 'https://raw.githubusercontent.com/Tyox-all/weave-intel/main/mitre-llm.json',
|
|
352
|
+
description: 'MITRE ATT&CK techniques adapted for LLM threats',
|
|
353
|
+
enabled: true,
|
|
354
|
+
autoUpdate: true,
|
|
355
|
+
updateIntervalHours: 168, // 7 days
|
|
356
|
+
patternCount: 0,
|
|
357
|
+
version: '0.0.0',
|
|
358
|
+
categories: [],
|
|
359
|
+
},
|
|
360
|
+
];
|
|
361
|
+
// ============================================================================
|
|
362
|
+
// Threat Intelligence Manager
|
|
363
|
+
// ============================================================================
|
|
364
|
+
export class ThreatIntelManager {
|
|
365
|
+
patterns = new Map();
|
|
366
|
+
sources = new Map();
|
|
367
|
+
initialized = false;
|
|
368
|
+
lastGlobalUpdate;
|
|
369
|
+
constructor() {
|
|
370
|
+
this.initialize();
|
|
371
|
+
}
|
|
372
|
+
initialize() {
|
|
373
|
+
// Load default sources
|
|
374
|
+
for (const source of DEFAULT_SOURCES) {
|
|
375
|
+
this.sources.set(source.id, { ...source });
|
|
376
|
+
}
|
|
377
|
+
// Load built-in patterns
|
|
378
|
+
for (const pattern of BUILTIN_PATTERNS) {
|
|
379
|
+
this.patterns.set(pattern.id, { ...pattern });
|
|
380
|
+
}
|
|
381
|
+
this.initialized = true;
|
|
382
|
+
this.lastGlobalUpdate = new Date();
|
|
383
|
+
}
|
|
384
|
+
// ==========================================================================
|
|
385
|
+
// Pattern Management
|
|
386
|
+
// ==========================================================================
|
|
387
|
+
getPatterns(options) {
|
|
388
|
+
let patterns = Array.from(this.patterns.values());
|
|
389
|
+
if (options?.enabledOnly) {
|
|
390
|
+
patterns = patterns.filter(p => p.enabled);
|
|
391
|
+
}
|
|
392
|
+
if (options?.category) {
|
|
393
|
+
patterns = patterns.filter(p => p.category === options.category);
|
|
394
|
+
}
|
|
395
|
+
if (options?.sourceId) {
|
|
396
|
+
patterns = patterns.filter(p => p.sourceId === options.sourceId);
|
|
397
|
+
}
|
|
398
|
+
if (options?.minSeverity) {
|
|
399
|
+
const severityOrder = ['low', 'medium', 'high', 'critical'];
|
|
400
|
+
const minIndex = severityOrder.indexOf(options.minSeverity);
|
|
401
|
+
patterns = patterns.filter(p => severityOrder.indexOf(p.severity) >= minIndex);
|
|
402
|
+
}
|
|
403
|
+
return patterns;
|
|
404
|
+
}
|
|
405
|
+
getPattern(id) {
|
|
406
|
+
return this.patterns.get(id);
|
|
407
|
+
}
|
|
408
|
+
togglePattern(id, enabled) {
|
|
409
|
+
const pattern = this.patterns.get(id);
|
|
410
|
+
if (!pattern) {
|
|
411
|
+
return { success: false, error: `Pattern not found: ${id}` };
|
|
412
|
+
}
|
|
413
|
+
pattern.enabled = enabled;
|
|
414
|
+
pattern.updatedAt = new Date();
|
|
415
|
+
return { success: true };
|
|
416
|
+
}
|
|
417
|
+
// ==========================================================================
|
|
418
|
+
// Source Management
|
|
419
|
+
// ==========================================================================
|
|
420
|
+
getSources() {
|
|
421
|
+
return Array.from(this.sources.values());
|
|
422
|
+
}
|
|
423
|
+
getSource(id) {
|
|
424
|
+
return this.sources.get(id);
|
|
425
|
+
}
|
|
426
|
+
addSource(config) {
|
|
427
|
+
if (this.sources.has(config.id)) {
|
|
428
|
+
return { success: false, error: `Source already exists: ${config.id}` };
|
|
429
|
+
}
|
|
430
|
+
const newSource = {
|
|
431
|
+
id: config.id,
|
|
432
|
+
name: config.name,
|
|
433
|
+
type: config.type,
|
|
434
|
+
url: config.url,
|
|
435
|
+
description: config.description,
|
|
436
|
+
enabled: config.enabled ?? true,
|
|
437
|
+
autoUpdate: config.autoUpdate ?? true,
|
|
438
|
+
updateIntervalHours: config.updateIntervalHours ?? 24,
|
|
439
|
+
patternCount: 0,
|
|
440
|
+
version: '0.0.0',
|
|
441
|
+
categories: config.categories ?? [],
|
|
442
|
+
};
|
|
443
|
+
this.sources.set(config.id, newSource);
|
|
444
|
+
return { success: true };
|
|
445
|
+
}
|
|
446
|
+
removeSource(id) {
|
|
447
|
+
const source = this.sources.get(id);
|
|
448
|
+
if (!source) {
|
|
449
|
+
return { success: false, error: `Source not found: ${id}` };
|
|
450
|
+
}
|
|
451
|
+
if (source.type === 'weave_official') {
|
|
452
|
+
return { success: false, error: 'Cannot remove official Weave sources' };
|
|
453
|
+
}
|
|
454
|
+
// Remove all patterns from this source
|
|
455
|
+
for (const [patternId, pattern] of this.patterns) {
|
|
456
|
+
if (pattern.sourceId === id) {
|
|
457
|
+
this.patterns.delete(patternId);
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
this.sources.delete(id);
|
|
461
|
+
return { success: true };
|
|
462
|
+
}
|
|
463
|
+
// ==========================================================================
|
|
464
|
+
// Update Management
|
|
465
|
+
// ==========================================================================
|
|
466
|
+
async updateSource(sourceId, force = false) {
|
|
467
|
+
const startTime = Date.now();
|
|
468
|
+
const source = this.sources.get(sourceId);
|
|
469
|
+
if (!source) {
|
|
470
|
+
return {
|
|
471
|
+
sourceId,
|
|
472
|
+
sourceName: 'Unknown',
|
|
473
|
+
success: false,
|
|
474
|
+
previousVersion: '',
|
|
475
|
+
newVersion: '',
|
|
476
|
+
patternsAdded: 0,
|
|
477
|
+
patternsUpdated: 0,
|
|
478
|
+
patternsRemoved: 0,
|
|
479
|
+
totalPatterns: 0,
|
|
480
|
+
timestamp: new Date(),
|
|
481
|
+
error: `Source not found: ${sourceId}`,
|
|
482
|
+
duration_ms: Date.now() - startTime,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
if (source.type === 'weave_official') {
|
|
486
|
+
return {
|
|
487
|
+
sourceId,
|
|
488
|
+
sourceName: source.name,
|
|
489
|
+
success: true,
|
|
490
|
+
previousVersion: source.version,
|
|
491
|
+
newVersion: source.version,
|
|
492
|
+
patternsAdded: 0,
|
|
493
|
+
patternsUpdated: 0,
|
|
494
|
+
patternsRemoved: 0,
|
|
495
|
+
totalPatterns: this.countPatternsForSource(sourceId),
|
|
496
|
+
timestamp: new Date(),
|
|
497
|
+
duration_ms: Date.now() - startTime,
|
|
498
|
+
};
|
|
499
|
+
}
|
|
500
|
+
if (!source.url) {
|
|
501
|
+
return {
|
|
502
|
+
sourceId,
|
|
503
|
+
sourceName: source.name,
|
|
504
|
+
success: false,
|
|
505
|
+
previousVersion: source.version,
|
|
506
|
+
newVersion: source.version,
|
|
507
|
+
patternsAdded: 0,
|
|
508
|
+
patternsUpdated: 0,
|
|
509
|
+
patternsRemoved: 0,
|
|
510
|
+
totalPatterns: this.countPatternsForSource(sourceId),
|
|
511
|
+
timestamp: new Date(),
|
|
512
|
+
error: 'Source has no URL configured',
|
|
513
|
+
duration_ms: Date.now() - startTime,
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
// Check if update is needed
|
|
517
|
+
if (!force && source.lastUpdated) {
|
|
518
|
+
const hoursSinceUpdate = (Date.now() - source.lastUpdated.getTime()) / (1000 * 60 * 60);
|
|
519
|
+
if (hoursSinceUpdate < source.updateIntervalHours) {
|
|
520
|
+
return {
|
|
521
|
+
sourceId,
|
|
522
|
+
sourceName: source.name,
|
|
523
|
+
success: true,
|
|
524
|
+
previousVersion: source.version,
|
|
525
|
+
newVersion: source.version,
|
|
526
|
+
patternsAdded: 0,
|
|
527
|
+
patternsUpdated: 0,
|
|
528
|
+
patternsRemoved: 0,
|
|
529
|
+
totalPatterns: this.countPatternsForSource(sourceId),
|
|
530
|
+
timestamp: new Date(),
|
|
531
|
+
duration_ms: Date.now() - startTime,
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
try {
|
|
536
|
+
const response = await fetch(source.url);
|
|
537
|
+
if (!response.ok) {
|
|
538
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
539
|
+
}
|
|
540
|
+
const data = await response.json();
|
|
541
|
+
const previousVersion = source.version;
|
|
542
|
+
let patternsAdded = 0;
|
|
543
|
+
let patternsUpdated = 0;
|
|
544
|
+
if (data.patterns && Array.isArray(data.patterns)) {
|
|
545
|
+
for (const p of data.patterns) {
|
|
546
|
+
if (!p.id || !p.pattern)
|
|
547
|
+
continue;
|
|
548
|
+
const patternId = `${sourceId}_${p.id}`;
|
|
549
|
+
const existing = this.patterns.get(patternId);
|
|
550
|
+
const pattern = {
|
|
551
|
+
id: patternId,
|
|
552
|
+
sourceId,
|
|
553
|
+
category: p.category || 'prompt_injection',
|
|
554
|
+
name: p.name || p.id,
|
|
555
|
+
description: p.description || '',
|
|
556
|
+
patternType: 'regex',
|
|
557
|
+
pattern: p.pattern,
|
|
558
|
+
severity: p.severity || 'medium',
|
|
559
|
+
confidence: 0.8,
|
|
560
|
+
mitreId: p.mitreId,
|
|
561
|
+
mitreTactic: p.mitreTactic,
|
|
562
|
+
mitreTechnique: p.mitreTechnique,
|
|
563
|
+
tags: p.tags || [],
|
|
564
|
+
enabled: true,
|
|
565
|
+
version: data.version || '1.0.0',
|
|
566
|
+
createdAt: existing?.createdAt || new Date(),
|
|
567
|
+
updatedAt: new Date(),
|
|
568
|
+
};
|
|
569
|
+
this.patterns.set(patternId, pattern);
|
|
570
|
+
if (existing) {
|
|
571
|
+
patternsUpdated++;
|
|
572
|
+
}
|
|
573
|
+
else {
|
|
574
|
+
patternsAdded++;
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
// Update source metadata
|
|
579
|
+
source.lastUpdated = new Date();
|
|
580
|
+
source.patternCount = this.countPatternsForSource(sourceId);
|
|
581
|
+
source.version = data.version || '1.0.0';
|
|
582
|
+
source.lastError = undefined;
|
|
583
|
+
this.lastGlobalUpdate = new Date();
|
|
584
|
+
return {
|
|
585
|
+
sourceId,
|
|
586
|
+
sourceName: source.name,
|
|
587
|
+
success: true,
|
|
588
|
+
previousVersion,
|
|
589
|
+
newVersion: source.version,
|
|
590
|
+
patternsAdded,
|
|
591
|
+
patternsUpdated,
|
|
592
|
+
patternsRemoved: 0,
|
|
593
|
+
totalPatterns: source.patternCount,
|
|
594
|
+
timestamp: new Date(),
|
|
595
|
+
duration_ms: Date.now() - startTime,
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
catch (error) {
|
|
599
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
600
|
+
source.lastError = errorMsg;
|
|
601
|
+
return {
|
|
602
|
+
sourceId,
|
|
603
|
+
sourceName: source.name,
|
|
604
|
+
success: false,
|
|
605
|
+
previousVersion: source.version,
|
|
606
|
+
newVersion: source.version,
|
|
607
|
+
patternsAdded: 0,
|
|
608
|
+
patternsUpdated: 0,
|
|
609
|
+
patternsRemoved: 0,
|
|
610
|
+
totalPatterns: this.countPatternsForSource(sourceId),
|
|
611
|
+
timestamp: new Date(),
|
|
612
|
+
error: errorMsg,
|
|
613
|
+
duration_ms: Date.now() - startTime,
|
|
614
|
+
};
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
async updateAllSources(force = false) {
|
|
618
|
+
const startTime = Date.now();
|
|
619
|
+
const results = [];
|
|
620
|
+
for (const source of this.sources.values()) {
|
|
621
|
+
if (source.autoUpdate || force) {
|
|
622
|
+
const result = await this.updateSource(source.id, force);
|
|
623
|
+
results.push(result);
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
return {
|
|
627
|
+
totalSources: results.length,
|
|
628
|
+
successfulUpdates: results.filter(r => r.success).length,
|
|
629
|
+
failedUpdates: results.filter(r => !r.success).length,
|
|
630
|
+
totalPatternsAdded: results.reduce((sum, r) => sum + r.patternsAdded, 0),
|
|
631
|
+
totalPatternsUpdated: results.reduce((sum, r) => sum + r.patternsUpdated, 0),
|
|
632
|
+
totalPatternsRemoved: results.reduce((sum, r) => sum + r.patternsRemoved, 0),
|
|
633
|
+
results,
|
|
634
|
+
timestamp: new Date(),
|
|
635
|
+
duration_ms: Date.now() - startTime,
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
countPatternsForSource(sourceId) {
|
|
639
|
+
return Array.from(this.patterns.values()).filter(p => p.sourceId === sourceId).length;
|
|
640
|
+
}
|
|
641
|
+
// ==========================================================================
|
|
642
|
+
// Scanning
|
|
643
|
+
// ==========================================================================
|
|
644
|
+
scan(content, config) {
|
|
645
|
+
const startTime = Date.now();
|
|
646
|
+
const matches = [];
|
|
647
|
+
const severityOrder = ['low', 'medium', 'high', 'critical'];
|
|
648
|
+
const minSeverityIndex = config?.minSeverity
|
|
649
|
+
? severityOrder.indexOf(config.minSeverity)
|
|
650
|
+
: 0;
|
|
651
|
+
const minConfidence = config?.minConfidence ?? 0;
|
|
652
|
+
for (const pattern of this.patterns.values()) {
|
|
653
|
+
if (!pattern.enabled)
|
|
654
|
+
continue;
|
|
655
|
+
// Filter by category
|
|
656
|
+
if (config?.categories && !config.categories.includes(pattern.category)) {
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
// Filter by severity
|
|
660
|
+
if (severityOrder.indexOf(pattern.severity) < minSeverityIndex)
|
|
661
|
+
continue;
|
|
662
|
+
// Filter by confidence
|
|
663
|
+
if (pattern.confidence < minConfidence)
|
|
664
|
+
continue;
|
|
665
|
+
// Check pattern
|
|
666
|
+
try {
|
|
667
|
+
const regex = new RegExp(pattern.pattern, 'gi');
|
|
668
|
+
let match;
|
|
669
|
+
while ((match = regex.exec(content)) !== null) {
|
|
670
|
+
matches.push({
|
|
671
|
+
patternId: pattern.id,
|
|
672
|
+
patternName: pattern.name,
|
|
673
|
+
category: pattern.category,
|
|
674
|
+
severity: pattern.severity,
|
|
675
|
+
confidence: pattern.confidence,
|
|
676
|
+
matchedText: match[0].substring(0, 100),
|
|
677
|
+
position: { start: match.index, end: match.index + match[0].length },
|
|
678
|
+
mitreId: pattern.mitreId,
|
|
679
|
+
mitreTactic: pattern.mitreTactic,
|
|
680
|
+
recommendation: `Review content for ${pattern.category} attempt`,
|
|
681
|
+
});
|
|
682
|
+
if (config?.maxMatches && matches.length >= config.maxMatches)
|
|
683
|
+
break;
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
catch {
|
|
687
|
+
// Invalid regex, skip
|
|
688
|
+
}
|
|
689
|
+
if (config?.maxMatches && matches.length >= config.maxMatches)
|
|
690
|
+
break;
|
|
691
|
+
}
|
|
692
|
+
// Sort by severity (critical first)
|
|
693
|
+
matches.sort((a, b) => severityOrder.indexOf(b.severity) - severityOrder.indexOf(a.severity));
|
|
694
|
+
// Build summary
|
|
695
|
+
const bySeverity = { low: 0, medium: 0, high: 0, critical: 0 };
|
|
696
|
+
const byCategory = {};
|
|
697
|
+
const mitreTechniques = [];
|
|
698
|
+
for (const m of matches) {
|
|
699
|
+
bySeverity[m.severity]++;
|
|
700
|
+
byCategory[m.category] = (byCategory[m.category] || 0) + 1;
|
|
701
|
+
if (m.mitreId && !mitreTechniques.includes(m.mitreId)) {
|
|
702
|
+
mitreTechniques.push(m.mitreId);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
const highestSeverity = matches.length > 0 ? matches[0].severity : null;
|
|
706
|
+
return {
|
|
707
|
+
scanned: true,
|
|
708
|
+
content_length: content.length,
|
|
709
|
+
matches,
|
|
710
|
+
summary: {
|
|
711
|
+
total_matches: matches.length,
|
|
712
|
+
by_severity: bySeverity,
|
|
713
|
+
by_category: byCategory,
|
|
714
|
+
highest_severity: highestSeverity,
|
|
715
|
+
mitre_techniques: mitreTechniques,
|
|
716
|
+
},
|
|
717
|
+
recommendations: matches.length > 0
|
|
718
|
+
? [`Found ${matches.length} potential threat(s). Review flagged content.`]
|
|
719
|
+
: ['No threats detected.'],
|
|
720
|
+
scan_duration_ms: Date.now() - startTime,
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
// ==========================================================================
|
|
724
|
+
// Status
|
|
725
|
+
// ==========================================================================
|
|
726
|
+
getStatus() {
|
|
727
|
+
const patterns = Array.from(this.patterns.values());
|
|
728
|
+
const sources = Array.from(this.sources.values());
|
|
729
|
+
const enabledPatterns = patterns.filter(p => p.enabled);
|
|
730
|
+
// Count by category
|
|
731
|
+
const byCategory = {
|
|
732
|
+
prompt_injection: 0,
|
|
733
|
+
jailbreak: 0,
|
|
734
|
+
data_exfiltration: 0,
|
|
735
|
+
privilege_escalation: 0,
|
|
736
|
+
social_engineering: 0,
|
|
737
|
+
malicious_code: 0,
|
|
738
|
+
pii_extraction: 0,
|
|
739
|
+
system_prompt_leak: 0,
|
|
740
|
+
dos_attack: 0,
|
|
741
|
+
mcp_exploit: 0,
|
|
742
|
+
};
|
|
743
|
+
const bySeverity = { low: 0, medium: 0, high: 0, critical: 0 };
|
|
744
|
+
const bySource = {};
|
|
745
|
+
const mitreTactics = new Set();
|
|
746
|
+
const mitreTechniques = new Set();
|
|
747
|
+
const categories = new Set();
|
|
748
|
+
for (const pattern of enabledPatterns) {
|
|
749
|
+
byCategory[pattern.category]++;
|
|
750
|
+
bySeverity[pattern.severity]++;
|
|
751
|
+
bySource[pattern.sourceId] = (bySource[pattern.sourceId] || 0) + 1;
|
|
752
|
+
categories.add(pattern.category);
|
|
753
|
+
if (pattern.mitreTactic)
|
|
754
|
+
mitreTactics.add(pattern.mitreTactic);
|
|
755
|
+
if (pattern.mitreId)
|
|
756
|
+
mitreTechniques.add(pattern.mitreId);
|
|
757
|
+
}
|
|
758
|
+
// Check health
|
|
759
|
+
const staleSources = [];
|
|
760
|
+
const failedSources = [];
|
|
761
|
+
let oldestUpdate;
|
|
762
|
+
for (const source of sources) {
|
|
763
|
+
if (source.lastError)
|
|
764
|
+
failedSources.push(source.id);
|
|
765
|
+
if (source.autoUpdate && source.lastUpdated) {
|
|
766
|
+
const hoursSinceUpdate = (Date.now() - source.lastUpdated.getTime()) / (1000 * 60 * 60);
|
|
767
|
+
if (hoursSinceUpdate > source.updateIntervalHours * 2) {
|
|
768
|
+
staleSources.push(source.id);
|
|
769
|
+
}
|
|
770
|
+
if (!oldestUpdate || source.lastUpdated < oldestUpdate) {
|
|
771
|
+
oldestUpdate = source.lastUpdated;
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
const healthStatus = failedSources.length > 0 ? 'degraded'
|
|
776
|
+
: staleSources.length > 0 ? 'stale'
|
|
777
|
+
: 'healthy';
|
|
778
|
+
return {
|
|
779
|
+
initialized: this.initialized,
|
|
780
|
+
lastGlobalUpdate: this.lastGlobalUpdate,
|
|
781
|
+
sources: {
|
|
782
|
+
total: sources.length,
|
|
783
|
+
enabled: sources.filter(s => s.enabled).length,
|
|
784
|
+
autoUpdate: sources.filter(s => s.autoUpdate).length,
|
|
785
|
+
},
|
|
786
|
+
patterns: {
|
|
787
|
+
total: patterns.length,
|
|
788
|
+
byCategory,
|
|
789
|
+
bySeverity,
|
|
790
|
+
bySource,
|
|
791
|
+
},
|
|
792
|
+
coverage: {
|
|
793
|
+
mitreAttack: {
|
|
794
|
+
tactics: mitreTactics.size,
|
|
795
|
+
techniques: mitreTechniques.size,
|
|
796
|
+
},
|
|
797
|
+
categories: Array.from(categories),
|
|
798
|
+
},
|
|
799
|
+
health: {
|
|
800
|
+
status: healthStatus,
|
|
801
|
+
oldestUpdate,
|
|
802
|
+
staleSources,
|
|
803
|
+
failedSources,
|
|
804
|
+
},
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
// ============================================================================
|
|
809
|
+
// Singleton Export
|
|
810
|
+
// ============================================================================
|
|
811
|
+
export const threatIntel = new ThreatIntelManager();
|
|
812
|
+
//# sourceMappingURL=threat-intel-manager.js.map
|