agentshield-sdk 7.4.0 → 10.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.
- package/CHANGELOG.md +48 -0
- package/LICENSE +21 -21
- package/README.md +30 -37
- package/bin/agentshield-audit +51 -0
- package/package.json +7 -9
- package/src/adaptive.js +330 -330
- package/src/agent-intent.js +807 -0
- package/src/alert-tuning.js +480 -480
- package/src/audit-streaming.js +1 -1
- package/src/badges.js +196 -196
- package/src/behavioral-dna.js +12 -0
- package/src/canary.js +2 -3
- package/src/certification.js +563 -563
- package/src/circuit-breaker.js +2 -2
- package/src/confused-deputy.js +4 -0
- package/src/conversation.js +494 -494
- package/src/cross-turn.js +649 -0
- package/src/ctf.js +462 -462
- package/src/detector-core.js +71 -152
- package/src/document-scanner.js +795 -795
- package/src/drift-monitor.js +344 -0
- package/src/encoding.js +429 -429
- package/src/ensemble.js +523 -0
- package/src/enterprise.js +405 -405
- package/src/flight-recorder.js +2 -0
- package/src/i18n-patterns.js +523 -523
- package/src/index.js +19 -0
- package/src/main.js +79 -6
- package/src/mcp-guard.js +974 -0
- package/src/micro-model.js +762 -0
- package/src/ml-detector.js +316 -0
- package/src/model-finetuning.js +884 -884
- package/src/multimodal.js +296 -296
- package/src/nist-mapping.js +2 -2
- package/src/observability.js +330 -330
- package/src/openclaw.js +450 -450
- package/src/otel.js +544 -544
- package/src/owasp-2025.js +1 -1
- package/src/owasp-agentic.js +420 -0
- package/src/persistent-learning.js +677 -0
- package/src/plugin-marketplace.js +628 -628
- package/src/plugin-system.js +349 -349
- package/src/policy-extended.js +635 -635
- package/src/policy.js +443 -443
- package/src/prompt-leakage.js +2 -2
- package/src/real-attack-datasets.js +2 -2
- package/src/redteam-cli.js +439 -0
- package/src/self-training.js +772 -0
- package/src/smart-config.js +812 -0
- package/src/supply-chain-scanner.js +691 -0
- package/src/testing.js +5 -1
- package/src/threat-encyclopedia.js +629 -629
- package/src/threat-intel-network.js +1017 -1017
- package/src/token-analysis.js +467 -467
- package/src/tool-output-validator.js +354 -354
- package/src/watermark.js +1 -2
- package/types/index.d.ts +660 -0
package/src/owasp-2025.js
CHANGED
|
@@ -268,7 +268,7 @@ class OWASPCoverageMatrix {
|
|
|
268
268
|
achievedWeight += weight * multiplier;
|
|
269
269
|
}
|
|
270
270
|
|
|
271
|
-
const percentage = Math.round((achievedWeight / totalWeight) * 100);
|
|
271
|
+
const percentage = totalWeight > 0 ? Math.round((achievedWeight / totalWeight) * 100) : 0;
|
|
272
272
|
let grade;
|
|
273
273
|
if (percentage >= 90) grade = 'A';
|
|
274
274
|
else if (percentage >= 80) grade = 'B';
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Agent Shield — OWASP Agentic Applications Top 10 (2026) Scanner
|
|
5
|
+
*
|
|
6
|
+
* Scans agent interactions for all 10 OWASP Agentic risks:
|
|
7
|
+
* ASI01 Agent Goal Hijack
|
|
8
|
+
* ASI02 Tool Misuse
|
|
9
|
+
* ASI03 Identity & Privilege Abuse
|
|
10
|
+
* ASI04 Supply Chain Compromise
|
|
11
|
+
* ASI05 Unexpected Code Execution
|
|
12
|
+
* ASI06 Memory & Context Poisoning
|
|
13
|
+
* ASI07 Insecure Inter-Agent Communication
|
|
14
|
+
* ASI08 Cascading Failures
|
|
15
|
+
* ASI09 Human-Agent Trust Exploitation
|
|
16
|
+
* ASI10 Rogue Agents
|
|
17
|
+
*
|
|
18
|
+
* Produces aggregate 0-100 score, JSON/Markdown/SARIF reports, and CI/CD exit codes.
|
|
19
|
+
*
|
|
20
|
+
* All detection runs locally — no data ever leaves your environment.
|
|
21
|
+
*
|
|
22
|
+
* @module owasp-agentic
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const { scanText } = require('./detector-core');
|
|
26
|
+
|
|
27
|
+
// =========================================================================
|
|
28
|
+
// RISK DEFINITIONS
|
|
29
|
+
// =========================================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* OWASP Agentic Top 10 risk definitions with detection patterns.
|
|
33
|
+
*/
|
|
34
|
+
const OWASP_AGENTIC_2026 = Object.freeze([
|
|
35
|
+
{
|
|
36
|
+
id: 'ASI01',
|
|
37
|
+
name: 'Agent Goal Hijack',
|
|
38
|
+
severity: 'critical',
|
|
39
|
+
description: 'Attacker manipulates the agent into pursuing unauthorized objectives by overriding system instructions.',
|
|
40
|
+
patterns: [
|
|
41
|
+
/ignore\s+(all\s+)?(previous|prior)\s+(instructions|rules|objectives)/i,
|
|
42
|
+
/your\s+new\s+(goal|objective|mission|purpose)\s+is/i,
|
|
43
|
+
/forget\s+(your|all)\s+(instructions|training|goals)/i,
|
|
44
|
+
/override\s+(system|safety)\s+(prompt|instructions|objectives)/i,
|
|
45
|
+
/disregard\s+(all\s+)?(previous|prior|your)\s+(instructions|rules)/i
|
|
46
|
+
],
|
|
47
|
+
remediation: 'Pin immutable system objectives via constitutional AI techniques. Reject override directives. Implement goal integrity checksums.'
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
id: 'ASI02',
|
|
51
|
+
name: 'Tool Misuse',
|
|
52
|
+
severity: 'high',
|
|
53
|
+
description: 'Agent tools are invoked in unintended ways — dangerous commands, unauthorized parameters, or chained abuse.',
|
|
54
|
+
patterns: [
|
|
55
|
+
/run\s+(?:shell|cmd|terminal|bash)/i,
|
|
56
|
+
/rm\s+-rf/i,
|
|
57
|
+
/curl\s+.*\|\s*(?:bash|sh)/i,
|
|
58
|
+
/execute\s+(?:arbitrary|any)\s+(?:code|command)/i,
|
|
59
|
+
/drop\s+table/i,
|
|
60
|
+
/chmod\s+777/i
|
|
61
|
+
],
|
|
62
|
+
remediation: 'Enforce least-privilege tool access. Maintain command allowlists. Require confirmation for destructive operations.'
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'ASI03',
|
|
66
|
+
name: 'Identity & Privilege Abuse',
|
|
67
|
+
severity: 'critical',
|
|
68
|
+
description: 'Agent assumes unauthorized identity or escalates privileges beyond its granted scope.',
|
|
69
|
+
patterns: [
|
|
70
|
+
/act\s+as\s+admin/i,
|
|
71
|
+
/sudo\s+/i,
|
|
72
|
+
/root\s+access/i,
|
|
73
|
+
/grant\s+(me\s+)?(admin|root|superuser)/i,
|
|
74
|
+
/escalate\s+(my\s+)?privilege/i,
|
|
75
|
+
/impersonate\s+/i,
|
|
76
|
+
/admin\s+override\s+code/i
|
|
77
|
+
],
|
|
78
|
+
remediation: 'Require strong identity verification. Use signed delegation tokens with expiry. Enforce RBAC boundaries.'
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'ASI04',
|
|
82
|
+
name: 'Supply Chain Compromise',
|
|
83
|
+
severity: 'high',
|
|
84
|
+
description: 'Malicious or tampered tools, plugins, or MCP servers introduced into the agent pipeline.',
|
|
85
|
+
patterns: [
|
|
86
|
+
/download\s+and\s+execute/i,
|
|
87
|
+
/unverified\s+plugin/i,
|
|
88
|
+
/install\s+from\s+untrusted/i,
|
|
89
|
+
/pip\s+install\s+.*--trusted-host/i,
|
|
90
|
+
/npm\s+install\s+.*--ignore-scripts/i
|
|
91
|
+
],
|
|
92
|
+
remediation: 'Require signed artifacts and hash-pinned dependencies. Verify MCP server attestation before use.'
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: 'ASI05',
|
|
96
|
+
name: 'Unexpected Code Execution',
|
|
97
|
+
severity: 'critical',
|
|
98
|
+
description: 'Agent or tool executes arbitrary code from untrusted input, enabling RCE.',
|
|
99
|
+
patterns: [
|
|
100
|
+
/eval\s*\(/i,
|
|
101
|
+
/new\s+Function\s*\(/i,
|
|
102
|
+
/child_process/i,
|
|
103
|
+
/exec\s*\(\s*['"`]/i,
|
|
104
|
+
/import\s*\(\s*['"`](?:https?:|data:)/i,
|
|
105
|
+
/process\.env/i
|
|
106
|
+
],
|
|
107
|
+
remediation: 'Disable dynamic code evaluation. Sandbox untrusted inputs. Use allowlisted interpreters only.'
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'ASI06',
|
|
111
|
+
name: 'Memory & Context Poisoning',
|
|
112
|
+
severity: 'high',
|
|
113
|
+
description: 'Attacker injects persistent malicious content into agent memory or conversation context.',
|
|
114
|
+
patterns: [
|
|
115
|
+
/store\s+this\s+forever/i,
|
|
116
|
+
/remember\s+(?:this\s+)?secret\s+instruction/i,
|
|
117
|
+
/add\s+to\s+(?:your\s+)?(?:memory|context|knowledge)/i,
|
|
118
|
+
/persistent\s+instruction/i,
|
|
119
|
+
/from\s+now\s+on\s+always/i
|
|
120
|
+
],
|
|
121
|
+
remediation: 'Validate all memory writes. Isolate trusted context from untrusted data. Implement memory integrity checks.'
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
id: 'ASI07',
|
|
125
|
+
name: 'Insecure Inter-Agent Communication',
|
|
126
|
+
severity: 'high',
|
|
127
|
+
description: 'Messages between agents lack authentication, integrity, or confidentiality protections.',
|
|
128
|
+
patterns: [
|
|
129
|
+
/forward\s+without\s+verification/i,
|
|
130
|
+
/unsigned\s+agent\s+message/i,
|
|
131
|
+
/trust\s+all\s+agents/i,
|
|
132
|
+
/skip\s+(?:message\s+)?(?:signing|verification|authentication)/i,
|
|
133
|
+
/relay\s+unverified/i
|
|
134
|
+
],
|
|
135
|
+
remediation: 'Use HMAC-signed messages with replay protection. Verify agent identity before processing delegated tasks.'
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
id: 'ASI08',
|
|
139
|
+
name: 'Cascading Failures',
|
|
140
|
+
severity: 'medium',
|
|
141
|
+
description: 'One agent failure propagates across the system, causing widespread disruption.',
|
|
142
|
+
patterns: [
|
|
143
|
+
/retry\s+forever/i,
|
|
144
|
+
/broadcast\s+to\s+all\s+agents/i,
|
|
145
|
+
/no\s+timeout/i,
|
|
146
|
+
/infinite\s+(?:loop|retry|recursion)/i,
|
|
147
|
+
/fan\s*-?\s*out\s+unlimited/i
|
|
148
|
+
],
|
|
149
|
+
remediation: 'Add circuit breakers, bounded retries, and blast-radius isolation. Set timeouts on all agent calls.'
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
id: 'ASI09',
|
|
153
|
+
name: 'Human-Agent Trust Exploitation',
|
|
154
|
+
severity: 'high',
|
|
155
|
+
description: 'Attacker exploits human trust in AI agent outputs to authorize harmful actions.',
|
|
156
|
+
patterns: [
|
|
157
|
+
/urgent:\s*approve\s+/i,
|
|
158
|
+
/ceo\s+(?:requested|authorized|approved)/i,
|
|
159
|
+
/emergency\s+(?:override|authorization)/i,
|
|
160
|
+
/skip\s+(?:human\s+)?(?:review|approval|verification)/i,
|
|
161
|
+
/pre-?\s*approved\s+by\s+(?:management|security)/i,
|
|
162
|
+
/already\s+verified\s+by/i
|
|
163
|
+
],
|
|
164
|
+
remediation: 'Require step-up verification for high-impact actions. Never auto-approve based on claimed authority in text.'
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 'ASI10',
|
|
168
|
+
name: 'Rogue Agents',
|
|
169
|
+
severity: 'critical',
|
|
170
|
+
description: 'Agent operates outside its intended boundaries — self-replicating, disabling monitoring, or acting autonomously.',
|
|
171
|
+
patterns: [
|
|
172
|
+
/self-?\s*replicate/i,
|
|
173
|
+
/disable\s+(?:safety\s+)?monitoring/i,
|
|
174
|
+
/spawn\s+(?:new\s+)?(?:agents?|copies|instances)\s+(?:without|no)\s+(?:approval|limit)/i,
|
|
175
|
+
/remove\s+(?:all\s+)?(?:guardrails|safety|restrictions)/i,
|
|
176
|
+
/operate\s+autonomously/i,
|
|
177
|
+
/kill\s+switch\s+disabled/i
|
|
178
|
+
],
|
|
179
|
+
remediation: 'Implement kill switches and attestation. Require human approval for agent spawning. Enable continuous behavioral monitoring.'
|
|
180
|
+
}
|
|
181
|
+
]);
|
|
182
|
+
|
|
183
|
+
/** Severity weights for scoring. */
|
|
184
|
+
const SEVERITY_WEIGHTS = { critical: 20, high: 12, medium: 8, low: 4 };
|
|
185
|
+
|
|
186
|
+
// =========================================================================
|
|
187
|
+
// OWASPAgenticScanner
|
|
188
|
+
// =========================================================================
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Scans text inputs against all 10 OWASP Agentic Top 10 risks.
|
|
192
|
+
*/
|
|
193
|
+
class OWASPAgenticScanner {
|
|
194
|
+
/**
|
|
195
|
+
* @param {object} [options]
|
|
196
|
+
* @param {number} [options.failThreshold=70] - Score below which scan is considered failed.
|
|
197
|
+
*/
|
|
198
|
+
constructor(options = {}) {
|
|
199
|
+
this.failThreshold = options.failThreshold != null ? options.failThreshold : 70;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Scan input text for OWASP Agentic risks.
|
|
204
|
+
*
|
|
205
|
+
* @param {string|object} input - Text or object to scan.
|
|
206
|
+
* @returns {{ score: number, exitCode: number, status: string, findings: Array<object>, summary: object }}
|
|
207
|
+
*/
|
|
208
|
+
scan(input) {
|
|
209
|
+
const text = typeof input === 'string' ? input : JSON.stringify(input || {});
|
|
210
|
+
const findings = [];
|
|
211
|
+
const matchedRisks = new Set();
|
|
212
|
+
|
|
213
|
+
// Check each OWASP Agentic risk
|
|
214
|
+
for (const risk of OWASP_AGENTIC_2026) {
|
|
215
|
+
for (const pattern of risk.patterns) {
|
|
216
|
+
if (pattern.test(text)) {
|
|
217
|
+
if (!matchedRisks.has(risk.id)) {
|
|
218
|
+
matchedRisks.add(risk.id);
|
|
219
|
+
findings.push({
|
|
220
|
+
riskId: risk.id,
|
|
221
|
+
name: risk.name,
|
|
222
|
+
severity: risk.severity,
|
|
223
|
+
description: risk.description,
|
|
224
|
+
remediation: risk.remediation,
|
|
225
|
+
evidence: this._extractEvidence(text, pattern)
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Also run detector-core for broader injection coverage
|
|
234
|
+
const generic = scanText(text, { source: 'owasp_agentic_scan', sensitivity: 'high' });
|
|
235
|
+
if (generic.threats && generic.threats.length > 0 && !matchedRisks.has('ASI01')) {
|
|
236
|
+
findings.push({
|
|
237
|
+
riskId: 'ASI01',
|
|
238
|
+
name: 'Agent Goal Hijack',
|
|
239
|
+
severity: 'high',
|
|
240
|
+
description: 'Generic prompt injection detected that could hijack agent goals.',
|
|
241
|
+
remediation: 'Block prompt-injection patterns in untrusted input.',
|
|
242
|
+
evidence: generic.threats[0].description || 'detector-core pattern match'
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const score = this._calculateScore(findings);
|
|
247
|
+
const exitCode = score < this.failThreshold ? 1 : 0;
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
score,
|
|
251
|
+
exitCode,
|
|
252
|
+
status: exitCode === 0 ? 'pass' : 'fail',
|
|
253
|
+
findings,
|
|
254
|
+
summary: this._buildSummary(findings),
|
|
255
|
+
risks: OWASP_AGENTIC_2026.map(r => ({
|
|
256
|
+
id: r.id,
|
|
257
|
+
name: r.name,
|
|
258
|
+
detected: matchedRisks.has(r.id)
|
|
259
|
+
}))
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Scan multiple inputs and aggregate results.
|
|
265
|
+
*
|
|
266
|
+
* @param {Array<string|object>} inputs
|
|
267
|
+
* @returns {object} Aggregate scan result.
|
|
268
|
+
*/
|
|
269
|
+
scanBatch(inputs) {
|
|
270
|
+
const allFindings = [];
|
|
271
|
+
const riskCounts = {};
|
|
272
|
+
const scores = [];
|
|
273
|
+
|
|
274
|
+
for (const input of (inputs || [])) {
|
|
275
|
+
const result = this.scan(input);
|
|
276
|
+
scores.push(result.score);
|
|
277
|
+
for (const finding of result.findings) {
|
|
278
|
+
allFindings.push(finding);
|
|
279
|
+
riskCounts[finding.riskId] = (riskCounts[finding.riskId] || 0) + 1;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Average per-input scores rather than penalizing cumulative findings
|
|
284
|
+
const score = scores.length > 0
|
|
285
|
+
? Math.round(scores.reduce((a, b) => a + b, 0) / scores.length)
|
|
286
|
+
: 100;
|
|
287
|
+
return {
|
|
288
|
+
inputCount: (inputs || []).length,
|
|
289
|
+
score,
|
|
290
|
+
exitCode: score < this.failThreshold ? 1 : 0,
|
|
291
|
+
status: score >= this.failThreshold ? 'pass' : 'fail',
|
|
292
|
+
findings: allFindings,
|
|
293
|
+
summary: this._buildSummary(allFindings),
|
|
294
|
+
riskCounts
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Format scan result as JSON string.
|
|
300
|
+
* @param {object} scanResult
|
|
301
|
+
* @returns {string}
|
|
302
|
+
*/
|
|
303
|
+
toJSON(scanResult) {
|
|
304
|
+
return JSON.stringify(scanResult, null, 2);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Format scan result as Markdown report.
|
|
309
|
+
* @param {object} scanResult
|
|
310
|
+
* @returns {string}
|
|
311
|
+
*/
|
|
312
|
+
toMarkdown(scanResult) {
|
|
313
|
+
const lines = [
|
|
314
|
+
'# OWASP Agentic Top 10 Scan',
|
|
315
|
+
'',
|
|
316
|
+
`- **Score:** ${scanResult.score}/100`,
|
|
317
|
+
`- **Status:** ${scanResult.status.toUpperCase()}`,
|
|
318
|
+
`- **Findings:** ${scanResult.findings.length}`,
|
|
319
|
+
''
|
|
320
|
+
];
|
|
321
|
+
|
|
322
|
+
if (scanResult.findings.length === 0) {
|
|
323
|
+
lines.push('No OWASP Agentic risks detected.');
|
|
324
|
+
return lines.join('\n');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
lines.push('## Findings');
|
|
328
|
+
lines.push('');
|
|
329
|
+
for (const finding of scanResult.findings) {
|
|
330
|
+
lines.push(`### ${finding.riskId}: ${finding.name} (${finding.severity})`);
|
|
331
|
+
lines.push(`- **Evidence:** ${finding.evidence}`);
|
|
332
|
+
lines.push(`- **Remediation:** ${finding.remediation}`);
|
|
333
|
+
lines.push('');
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
lines.push('## Summary');
|
|
337
|
+
const s = scanResult.summary;
|
|
338
|
+
lines.push(`| Severity | Count |`);
|
|
339
|
+
lines.push(`|----------|-------|`);
|
|
340
|
+
lines.push(`| Critical | ${s.critical} |`);
|
|
341
|
+
lines.push(`| High | ${s.high} |`);
|
|
342
|
+
lines.push(`| Medium | ${s.medium} |`);
|
|
343
|
+
lines.push(`| Low | ${s.low} |`);
|
|
344
|
+
|
|
345
|
+
return lines.join('\n');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Format scan result as SARIF 2.1.0 for CI/CD integration.
|
|
350
|
+
* @param {object} scanResult
|
|
351
|
+
* @returns {object} SARIF object.
|
|
352
|
+
*/
|
|
353
|
+
toSARIF(scanResult) {
|
|
354
|
+
const results = scanResult.findings.map(f => ({
|
|
355
|
+
ruleId: f.riskId,
|
|
356
|
+
level: f.severity === 'critical' ? 'error' : (f.severity === 'high' ? 'warning' : 'note'),
|
|
357
|
+
message: { text: `${f.name}: ${f.evidence}` },
|
|
358
|
+
properties: {
|
|
359
|
+
severity: f.severity,
|
|
360
|
+
remediation: f.remediation
|
|
361
|
+
}
|
|
362
|
+
}));
|
|
363
|
+
|
|
364
|
+
return {
|
|
365
|
+
version: '2.1.0',
|
|
366
|
+
$schema: 'https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json',
|
|
367
|
+
runs: [{
|
|
368
|
+
tool: {
|
|
369
|
+
driver: {
|
|
370
|
+
name: 'Agent Shield OWASP Agentic Scanner',
|
|
371
|
+
version: '1.0.0',
|
|
372
|
+
rules: OWASP_AGENTIC_2026.map(r => ({
|
|
373
|
+
id: r.id,
|
|
374
|
+
name: r.name,
|
|
375
|
+
shortDescription: { text: r.name },
|
|
376
|
+
fullDescription: { text: r.description },
|
|
377
|
+
defaultConfiguration: { level: r.severity === 'critical' ? 'error' : 'warning' }
|
|
378
|
+
}))
|
|
379
|
+
}
|
|
380
|
+
},
|
|
381
|
+
results
|
|
382
|
+
}]
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
// -----------------------------------------------------------------------
|
|
387
|
+
// Private
|
|
388
|
+
// -----------------------------------------------------------------------
|
|
389
|
+
|
|
390
|
+
/** @private */
|
|
391
|
+
_calculateScore(findings) {
|
|
392
|
+
const penalty = findings.reduce((sum, f) => sum + (SEVERITY_WEIGHTS[f.severity] || 6), 0);
|
|
393
|
+
return Math.max(0, 100 - penalty);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** @private */
|
|
397
|
+
_buildSummary(findings) {
|
|
398
|
+
const out = { critical: 0, high: 0, medium: 0, low: 0 };
|
|
399
|
+
for (const f of findings) {
|
|
400
|
+
out[f.severity] = (out[f.severity] || 0) + 1;
|
|
401
|
+
}
|
|
402
|
+
return out;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
/** @private */
|
|
406
|
+
_extractEvidence(text, pattern) {
|
|
407
|
+
const match = text.match(pattern);
|
|
408
|
+
return match ? match[0].substring(0, 120) : 'pattern matched';
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// =========================================================================
|
|
413
|
+
// EXPORTS
|
|
414
|
+
// =========================================================================
|
|
415
|
+
|
|
416
|
+
module.exports = {
|
|
417
|
+
OWASPAgenticScanner,
|
|
418
|
+
OWASP_AGENTIC_2026,
|
|
419
|
+
SEVERITY_WEIGHTS
|
|
420
|
+
};
|