@weave_protocol/mund 0.1.12 → 0.2.0

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.
@@ -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