agentshield-sdk 7.0.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.
Files changed (84) hide show
  1. package/CHANGELOG.md +191 -0
  2. package/LICENSE +21 -0
  3. package/README.md +975 -0
  4. package/bin/agent-shield.js +680 -0
  5. package/package.json +118 -0
  6. package/src/adaptive.js +330 -0
  7. package/src/agent-protocol.js +998 -0
  8. package/src/alert-tuning.js +480 -0
  9. package/src/allowlist.js +603 -0
  10. package/src/audit-immutable.js +914 -0
  11. package/src/audit-streaming.js +469 -0
  12. package/src/badges.js +196 -0
  13. package/src/behavior-profiling.js +289 -0
  14. package/src/benchmark-harness.js +804 -0
  15. package/src/canary.js +271 -0
  16. package/src/certification.js +563 -0
  17. package/src/circuit-breaker.js +321 -0
  18. package/src/compliance.js +617 -0
  19. package/src/confidence-tuning.js +324 -0
  20. package/src/confused-deputy.js +624 -0
  21. package/src/context-scoring.js +360 -0
  22. package/src/conversation.js +494 -0
  23. package/src/cost-optimizer.js +1024 -0
  24. package/src/ctf.js +462 -0
  25. package/src/detector-core.js +1999 -0
  26. package/src/distributed.js +359 -0
  27. package/src/document-scanner.js +795 -0
  28. package/src/embedding.js +307 -0
  29. package/src/encoding.js +429 -0
  30. package/src/enterprise.js +405 -0
  31. package/src/errors.js +100 -0
  32. package/src/eu-ai-act.js +523 -0
  33. package/src/fuzzer.js +764 -0
  34. package/src/honeypot.js +328 -0
  35. package/src/i18n-patterns.js +523 -0
  36. package/src/index.js +430 -0
  37. package/src/integrations.js +528 -0
  38. package/src/llm-redteam.js +670 -0
  39. package/src/main.js +741 -0
  40. package/src/main.mjs +38 -0
  41. package/src/mcp-bridge.js +542 -0
  42. package/src/mcp-certification.js +846 -0
  43. package/src/mcp-sdk-integration.js +355 -0
  44. package/src/mcp-security-runtime.js +741 -0
  45. package/src/mcp-server.js +740 -0
  46. package/src/middleware.js +208 -0
  47. package/src/model-finetuning.js +884 -0
  48. package/src/model-fingerprint.js +1042 -0
  49. package/src/multi-agent-trust.js +453 -0
  50. package/src/multi-agent.js +404 -0
  51. package/src/multimodal.js +296 -0
  52. package/src/nist-mapping.js +505 -0
  53. package/src/observability.js +330 -0
  54. package/src/openclaw.js +450 -0
  55. package/src/otel.js +544 -0
  56. package/src/owasp-2025.js +483 -0
  57. package/src/pii.js +390 -0
  58. package/src/plugin-marketplace.js +628 -0
  59. package/src/plugin-system.js +349 -0
  60. package/src/policy-dsl.js +775 -0
  61. package/src/policy-extended.js +635 -0
  62. package/src/policy.js +443 -0
  63. package/src/presets.js +409 -0
  64. package/src/production.js +557 -0
  65. package/src/prompt-leakage.js +321 -0
  66. package/src/rag-vulnerability.js +579 -0
  67. package/src/redteam.js +475 -0
  68. package/src/response-handler.js +429 -0
  69. package/src/scanners.js +357 -0
  70. package/src/self-healing.js +363 -0
  71. package/src/semantic.js +339 -0
  72. package/src/shield-score.js +250 -0
  73. package/src/sso-saml.js +897 -0
  74. package/src/stream-scanner.js +806 -0
  75. package/src/testing.js +505 -0
  76. package/src/threat-encyclopedia.js +629 -0
  77. package/src/threat-intel-network.js +1017 -0
  78. package/src/token-analysis.js +467 -0
  79. package/src/tool-guard.js +412 -0
  80. package/src/tool-output-validator.js +354 -0
  81. package/src/utils.js +83 -0
  82. package/src/watermark.js +235 -0
  83. package/src/worker-scanner.js +601 -0
  84. package/types/index.d.ts +2088 -0
@@ -0,0 +1,483 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Agent Shield — OWASP LLM Top 10 v2025 Coverage Matrix
5
+ *
6
+ * Maps Agent Shield capabilities to the OWASP Top 10 for LLM Applications (2025).
7
+ * Provides coverage scoring, gap analysis, and compliance reporting.
8
+ *
9
+ * All processing runs locally — no data ever leaves your environment.
10
+ */
11
+
12
+ // =========================================================================
13
+ // OWASP LLM Top 10 v2025 Definition
14
+ // =========================================================================
15
+
16
+ /**
17
+ * The complete OWASP LLM Top 10 v2025 with Agent Shield coverage mapping.
18
+ * @type {Array<object>}
19
+ */
20
+ const OWASP_LLM_2025 = [
21
+ {
22
+ id: 'LLM01',
23
+ name: 'Prompt Injection',
24
+ description: 'Manipulating LLMs via crafted inputs that override system instructions or cause unintended actions.',
25
+ severity: 'critical',
26
+ agentShieldModules: ['detector-core', 'middleware', 'integrations', 'i18n-patterns', 'encoding', 'conversation'],
27
+ coverageLevel: 'full',
28
+ mitigations: [
29
+ 'Real-time pattern matching against 60+ injection signatures',
30
+ 'Multi-language injection detection (CJK, Arabic, Cyrillic, Indic)',
31
+ 'Encoding bruteforce detection (base64, hex, unicode escapes)',
32
+ 'Fragmentation and language-switch detection',
33
+ 'Framework middleware for Anthropic, OpenAI, LangChain, Vercel AI',
34
+ 'Input quarantine for suspicious payloads'
35
+ ],
36
+ references: ['detector-core.js:INJECTION_PATTERNS', 'middleware.js:wrapAgent', 'i18n-patterns.js']
37
+ },
38
+ {
39
+ id: 'LLM02',
40
+ name: 'Sensitive Information Disclosure',
41
+ description: 'LLMs inadvertently revealing sensitive data such as PII, credentials, or proprietary information in responses.',
42
+ severity: 'critical',
43
+ agentShieldModules: ['pii', 'canary', 'watermark', 'prompt-leakage'],
44
+ coverageLevel: 'full',
45
+ mitigations: [
46
+ 'PII detection and redaction (SSN, credit cards, emails, phone numbers)',
47
+ 'DLP engine with configurable content policies',
48
+ 'API key pattern detection (AWS, GitHub, Stripe, etc.)',
49
+ 'Canary token injection and leak detection',
50
+ 'Output watermarking for traceability',
51
+ 'System prompt fingerprinting and leak scoring'
52
+ ],
53
+ references: ['pii.js:PIIRedactor', 'canary.js:CanaryTokens', 'prompt-leakage.js:SystemPromptGuard']
54
+ },
55
+ {
56
+ id: 'LLM03',
57
+ name: 'Supply Chain',
58
+ description: 'Vulnerabilities from third-party components, training data, pre-trained models, and deployment platforms.',
59
+ severity: 'high',
60
+ agentShieldModules: ['model-fingerprint', 'scanners', 'plugin-marketplace'],
61
+ coverageLevel: 'partial',
62
+ mitigations: [
63
+ 'Model fingerprinting via 16-feature stylistic analysis',
64
+ 'Supply chain detection with cosine similarity matching',
65
+ 'Plugin validation and sandboxing',
66
+ 'Tool schema validation for dangerous patterns'
67
+ ],
68
+ gaps: [
69
+ 'No model artifact binary scanning (e.g., pickle deserialization attacks)',
70
+ 'No model BOM (Bill of Materials) generation for model files',
71
+ 'No pre-trained model integrity verification (hash-based)'
72
+ ],
73
+ references: ['model-fingerprint.js:SupplyChainDetector', 'scanners.js:ToolSchemaValidator']
74
+ },
75
+ {
76
+ id: 'LLM04',
77
+ name: 'Data and Model Poisoning',
78
+ description: 'Manipulation of training data or model weights to introduce vulnerabilities, backdoors, or biases.',
79
+ severity: 'high',
80
+ agentShieldModules: ['scanners', 'self-healing', 'embedding', 'behavior-profiling'],
81
+ coverageLevel: 'partial',
82
+ mitigations: [
83
+ 'RAG document scanning for poisoned content',
84
+ 'Self-healing pattern generation from false negatives',
85
+ 'Embedding similarity detection for anomalous inputs',
86
+ 'Behavioral fingerprinting and anomaly detection (z-score)'
87
+ ],
88
+ gaps: [
89
+ 'No training data validation pipeline',
90
+ 'No model weight integrity verification',
91
+ 'No backdoor detection in fine-tuned models'
92
+ ],
93
+ references: ['scanners.js:RAGScanner', 'self-healing.js:SelfHealingEngine']
94
+ },
95
+ {
96
+ id: 'LLM05',
97
+ name: 'Improper Output Handling',
98
+ description: 'Insufficient validation of LLM outputs leading to XSS, SSRF, privilege escalation, or code execution.',
99
+ severity: 'high',
100
+ agentShieldModules: ['tool-output-validator', 'middleware', 'detector-core'],
101
+ coverageLevel: 'full',
102
+ mitigations: [
103
+ 'Output scanning for injection patterns in LLM responses',
104
+ 'Tool output validation and sanitization',
105
+ 'Express middleware for output filtering',
106
+ 'Content policy enforcement on outputs',
107
+ 'Structured data scanning for embedded threats'
108
+ ],
109
+ references: ['tool-output-validator.js:ToolOutputValidator', 'middleware.js:wrapAgent']
110
+ },
111
+ {
112
+ id: 'LLM06',
113
+ name: 'Excessive Agency',
114
+ description: 'Granting LLMs too much autonomy, capability, or permissions leading to unintended harmful actions.',
115
+ severity: 'critical',
116
+ agentShieldModules: ['tool-guard', 'multi-agent', 'multi-agent-trust', 'mcp-bridge'],
117
+ coverageLevel: 'full',
118
+ mitigations: [
119
+ 'Tool sequence analysis for suspicious call patterns',
120
+ 'Permission boundaries with allow/deny lists',
121
+ 'Agent firewall for inter-agent communication',
122
+ 'Delegation chain tracking and depth limits',
123
+ 'Capability tokens with expiration and scope limits',
124
+ 'Blast radius containment for agent failures',
125
+ 'MCP tool policy enforcement and session budgets'
126
+ ],
127
+ references: ['tool-guard.js:PermissionBoundary', 'multi-agent-trust.js:CapabilityToken', 'mcp-bridge.js:MCPToolPolicy']
128
+ },
129
+ {
130
+ id: 'LLM07',
131
+ name: 'System Prompt Leakage',
132
+ description: 'Extraction or disclosure of system prompts through direct queries, indirect techniques, or multi-step attacks.',
133
+ severity: 'high',
134
+ agentShieldModules: ['prompt-leakage', 'canary'],
135
+ coverageLevel: 'full',
136
+ mitigations: [
137
+ 'Dedicated prompt extraction attempt detection (30+ patterns)',
138
+ 'Direct, indirect, encoded, roleplay, and multi-step technique detection',
139
+ 'System prompt fingerprinting (n-gram overlap, key phrase matching)',
140
+ 'Output scanning for partial prompt leakage',
141
+ 'Canary token injection for leak tripwires',
142
+ 'Anti-extraction defense layer wrapping',
143
+ 'Decoy prompt generation for detected extraction attempts'
144
+ ],
145
+ references: ['prompt-leakage.js:SystemPromptGuard', 'canary.js:PromptLeakDetector']
146
+ },
147
+ {
148
+ id: 'LLM08',
149
+ name: 'Vector and Embedding Weaknesses',
150
+ description: 'Vulnerabilities in RAG systems including embedding manipulation, chunk boundary attacks, and retrieval poisoning.',
151
+ severity: 'high',
152
+ agentShieldModules: ['rag-vulnerability', 'embedding', 'scanners'],
153
+ coverageLevel: 'full',
154
+ mitigations: [
155
+ 'RAG-specific vulnerability scanning (chunk boundary, metadata injection)',
156
+ 'Embedding integrity checking and outlier detection',
157
+ 'Cross-document injection detection',
158
+ 'Context window stuffing assessment',
159
+ 'RAG pipeline security auditing',
160
+ 'Vector DB security checklist (Pinecone, Weaviate, Qdrant, Chroma, Milvus, pgvector)',
161
+ 'TF-IDF embedding similarity for anomaly detection'
162
+ ],
163
+ references: ['rag-vulnerability.js:RAGVulnerabilityScanner', 'embedding.js:EmbeddingSimilarityDetector']
164
+ },
165
+ {
166
+ id: 'LLM09',
167
+ name: 'Misinformation',
168
+ description: 'LLMs generating false or misleading content that appears authoritative, leading to misinformed decisions.',
169
+ severity: 'medium',
170
+ agentShieldModules: ['behavior-profiling', 'confidence-tuning', 'context-scoring'],
171
+ coverageLevel: 'partial',
172
+ mitigations: [
173
+ 'Behavioral fingerprinting and baseline deviation detection',
174
+ 'Per-category confidence threshold calibration',
175
+ 'Multi-turn conversation context analysis for consistency',
176
+ 'Escalation signal detection for topic manipulation'
177
+ ],
178
+ gaps: [
179
+ 'No factual grounding verification against knowledge bases',
180
+ 'No hallucination detection via source attribution',
181
+ 'No citation verification for claimed references'
182
+ ],
183
+ references: ['behavior-profiling.js:BehaviorProfile', 'confidence-tuning.js:ConfidenceTuner']
184
+ },
185
+ {
186
+ id: 'LLM10',
187
+ name: 'Unbounded Consumption',
188
+ description: 'LLM applications consuming excessive resources through large inputs, recursive operations, or resource exhaustion.',
189
+ severity: 'medium',
190
+ agentShieldModules: ['circuit-breaker', 'cost-optimizer', 'mcp-bridge'],
191
+ coverageLevel: 'full',
192
+ mitigations: [
193
+ 'Circuit breaker with configurable thresholds',
194
+ 'Rate limiter for request throttling',
195
+ 'Token budget analysis and enforcement',
196
+ '4-tier adaptive scanning with latency budgets',
197
+ 'MCP session guards with call/token budgets',
198
+ 'Input size limits (1MB default)',
199
+ 'Scan time budgets (200ms default)'
200
+ ],
201
+ references: ['circuit-breaker.js:CircuitBreaker', 'cost-optimizer.js:CostOptimizer']
202
+ }
203
+ ];
204
+
205
+ // =========================================================================
206
+ // Coverage weights per severity
207
+ // =========================================================================
208
+
209
+ const SEVERITY_WEIGHTS = {
210
+ critical: 15,
211
+ high: 10,
212
+ medium: 5
213
+ };
214
+
215
+ const COVERAGE_MULTIPLIERS = {
216
+ full: 1.0,
217
+ partial: 0.5,
218
+ planned: 0.1,
219
+ none: 0.0
220
+ };
221
+
222
+ // =========================================================================
223
+ // OWASPCoverageMatrix
224
+ // =========================================================================
225
+
226
+ class OWASPCoverageMatrix {
227
+ /**
228
+ * @param {object} [options]
229
+ * @param {object} [options.agentShield] - AgentShield instance for live validation
230
+ * @param {string} [options.organizationName] - Organization name for reports
231
+ */
232
+ constructor(options = {}) {
233
+ this.agentShield = options.agentShield || null;
234
+ this.organizationName = options.organizationName || 'Organization';
235
+ this.entries = OWASP_LLM_2025;
236
+ }
237
+
238
+ /**
239
+ * Returns the full coverage matrix with status for each OWASP entry.
240
+ * @returns {Array<object>}
241
+ */
242
+ getCoverage() {
243
+ return this.entries.map(entry => ({
244
+ id: entry.id,
245
+ name: entry.name,
246
+ severity: entry.severity,
247
+ coverageLevel: entry.coverageLevel,
248
+ modules: entry.agentShieldModules,
249
+ mitigationCount: entry.mitigations.length,
250
+ hasGaps: !!(entry.gaps && entry.gaps.length > 0),
251
+ gaps: entry.gaps || []
252
+ }));
253
+ }
254
+
255
+ /**
256
+ * Returns a percentage score (0–100) of OWASP coverage.
257
+ * Weighted by severity: critical items count more than medium.
258
+ * @returns {{ score: number, maxScore: number, percentage: number, grade: string }}
259
+ */
260
+ getCoverageScore() {
261
+ let totalWeight = 0;
262
+ let achievedWeight = 0;
263
+
264
+ for (const entry of this.entries) {
265
+ const weight = SEVERITY_WEIGHTS[entry.severity] || 5;
266
+ const multiplier = COVERAGE_MULTIPLIERS[entry.coverageLevel] || 0;
267
+ totalWeight += weight;
268
+ achievedWeight += weight * multiplier;
269
+ }
270
+
271
+ const percentage = Math.round((achievedWeight / totalWeight) * 100);
272
+ let grade;
273
+ if (percentage >= 90) grade = 'A';
274
+ else if (percentage >= 80) grade = 'B';
275
+ else if (percentage >= 70) grade = 'C';
276
+ else if (percentage >= 60) grade = 'D';
277
+ else grade = 'F';
278
+
279
+ return { score: achievedWeight, maxScore: totalWeight, percentage, grade };
280
+ }
281
+
282
+ /**
283
+ * Returns items where coverage is partial or planned.
284
+ * @returns {Array<object>}
285
+ */
286
+ getGaps() {
287
+ return this.entries
288
+ .filter(e => e.coverageLevel !== 'full')
289
+ .map(e => ({
290
+ id: e.id,
291
+ name: e.name,
292
+ severity: e.severity,
293
+ coverageLevel: e.coverageLevel,
294
+ gaps: e.gaps || [],
295
+ currentModules: e.agentShieldModules
296
+ }));
297
+ }
298
+
299
+ /**
300
+ * Returns actionable recommendations to improve OWASP coverage.
301
+ * @returns {Array<object>}
302
+ */
303
+ getRecommendations() {
304
+ const recs = [];
305
+
306
+ for (const entry of this.entries) {
307
+ if (entry.coverageLevel === 'full') continue;
308
+
309
+ const priority = entry.severity === 'critical' ? 'high' :
310
+ entry.severity === 'high' ? 'medium' : 'low';
311
+
312
+ recs.push({
313
+ id: entry.id,
314
+ name: entry.name,
315
+ priority,
316
+ currentCoverage: entry.coverageLevel,
317
+ gaps: entry.gaps || [],
318
+ recommendation: this._getRecommendation(entry)
319
+ });
320
+ }
321
+
322
+ return recs.sort((a, b) => {
323
+ const order = { high: 0, medium: 1, low: 2 };
324
+ return (order[a.priority] || 2) - (order[b.priority] || 2);
325
+ });
326
+ }
327
+
328
+ /**
329
+ * Validates scan results against OWASP coverage requirements.
330
+ * @param {object} scanResults - Results from AgentShield scan
331
+ * @returns {{ compliant: boolean, checkedItems: Array<object>, unchecked: Array<string> }}
332
+ */
333
+ validateCompliance(scanResults = {}) {
334
+ const checkedItems = [];
335
+ const unchecked = [];
336
+
337
+ for (const entry of this.entries) {
338
+ const isActive = this._isEntryActive(entry, scanResults);
339
+ if (isActive) {
340
+ checkedItems.push({ id: entry.id, name: entry.name, status: 'active' });
341
+ } else {
342
+ unchecked.push(entry.id);
343
+ }
344
+ }
345
+
346
+ return {
347
+ compliant: unchecked.length === 0,
348
+ checkedItems,
349
+ unchecked,
350
+ score: Math.round((checkedItems.length / this.entries.length) * 100)
351
+ };
352
+ }
353
+
354
+ /**
355
+ * Generates a formatted coverage report.
356
+ * @param {'text'|'json'|'markdown'} [format='text']
357
+ * @returns {string}
358
+ */
359
+ getCoverageReport(format = 'text') {
360
+ const score = this.getCoverageScore();
361
+ const gaps = this.getGaps();
362
+
363
+ if (format === 'json') {
364
+ return JSON.stringify({
365
+ framework: 'OWASP LLM Top 10',
366
+ version: '2025',
367
+ generatedAt: new Date().toISOString(),
368
+ organization: this.organizationName,
369
+ score,
370
+ coverage: this.getCoverage(),
371
+ gaps,
372
+ recommendations: this.getRecommendations()
373
+ }, null, 2);
374
+ }
375
+
376
+ if (format === 'markdown') {
377
+ return this._renderMarkdown(score, gaps);
378
+ }
379
+
380
+ return this._renderText(score, gaps);
381
+ }
382
+
383
+ // --- Private helpers ---
384
+
385
+ /** @private */
386
+ _getRecommendation(entry) {
387
+ const recs = {
388
+ LLM03: 'Add model artifact binary scanning (pickle, safetensors, ONNX) to detect deserialization attacks and backdoors. Generate AI-BOM for model supply chain.',
389
+ LLM04: 'Implement training data validation pipeline and model weight integrity verification. Add fine-tuning backdoor detection.',
390
+ LLM09: 'Add factual grounding verification, hallucination detection via source attribution, and citation verification.'
391
+ };
392
+ return recs[entry.id] || `Improve ${entry.name} coverage by addressing identified gaps.`;
393
+ }
394
+
395
+ /** @private */
396
+ _isEntryActive(entry, scanResults) {
397
+ if (!scanResults || typeof scanResults !== 'object') return false;
398
+ const activeModules = scanResults.activeModules || [];
399
+ return entry.agentShieldModules.some(m => activeModules.includes(m));
400
+ }
401
+
402
+ /** @private */
403
+ _renderText(score, gaps) {
404
+ const lines = [];
405
+ lines.push('╔══════════════════════════════════════════════════════════════╗');
406
+ lines.push('║ OWASP LLM Top 10 v2025 — Agent Shield Coverage ║');
407
+ lines.push('╚══════════════════════════════════════════════════════════════╝');
408
+ lines.push('');
409
+ lines.push(`Organization: ${this.organizationName}`);
410
+ lines.push(`Generated: ${new Date().toISOString()}`);
411
+ lines.push(`Score: ${score.percentage}% (Grade ${score.grade})`);
412
+ lines.push('');
413
+
414
+ for (const entry of this.entries) {
415
+ const icon = entry.coverageLevel === 'full' ? '●' :
416
+ entry.coverageLevel === 'partial' ? '◐' : '○';
417
+ const sev = entry.severity.toUpperCase().padEnd(8);
418
+ lines.push(` ${icon} ${entry.id} ${entry.name.padEnd(35)} [${sev}] ${entry.coverageLevel}`);
419
+ }
420
+
421
+ if (gaps.length > 0) {
422
+ lines.push('');
423
+ lines.push('── Gaps ──');
424
+ for (const gap of gaps) {
425
+ lines.push(` ${gap.id} ${gap.name}:`);
426
+ for (const g of gap.gaps) {
427
+ lines.push(` - ${g}`);
428
+ }
429
+ }
430
+ }
431
+
432
+ lines.push('');
433
+ lines.push(`Full: ${this.entries.filter(e => e.coverageLevel === 'full').length}/10 | Partial: ${this.entries.filter(e => e.coverageLevel === 'partial').length}/10`);
434
+ return lines.join('\n');
435
+ }
436
+
437
+ /** @private */
438
+ _renderMarkdown(score, gaps) {
439
+ const lines = [];
440
+ lines.push('# OWASP LLM Top 10 v2025 — Agent Shield Coverage Report');
441
+ lines.push('');
442
+ lines.push(`**Organization:** ${this.organizationName} `);
443
+ lines.push(`**Generated:** ${new Date().toISOString()} `);
444
+ lines.push(`**Score:** ${score.percentage}% (Grade ${score.grade})`);
445
+ lines.push('');
446
+ lines.push('## Coverage Matrix');
447
+ lines.push('');
448
+ lines.push('| ID | Risk | Severity | Coverage | Modules | Mitigations |');
449
+ lines.push('|----|------|----------|----------|---------|-------------|');
450
+
451
+ for (const entry of this.entries) {
452
+ const cov = entry.coverageLevel === 'full' ? 'Full' :
453
+ entry.coverageLevel === 'partial' ? 'Partial' : 'Planned';
454
+ lines.push(`| ${entry.id} | ${entry.name} | ${entry.severity} | ${cov} | ${entry.agentShieldModules.length} | ${entry.mitigations.length} |`);
455
+ }
456
+
457
+ if (gaps.length > 0) {
458
+ lines.push('');
459
+ lines.push('## Gaps & Recommendations');
460
+ lines.push('');
461
+ for (const gap of gaps) {
462
+ lines.push(`### ${gap.id} — ${gap.name} (${gap.coverageLevel})`);
463
+ for (const g of gap.gaps) {
464
+ lines.push(`- ${g}`);
465
+ }
466
+ lines.push('');
467
+ }
468
+ }
469
+
470
+ return lines.join('\n');
471
+ }
472
+ }
473
+
474
+ // =========================================================================
475
+ // Exports
476
+ // =========================================================================
477
+
478
+ module.exports = {
479
+ OWASP_LLM_2025,
480
+ OWASPCoverageMatrix,
481
+ SEVERITY_WEIGHTS,
482
+ COVERAGE_MULTIPLIERS
483
+ };