@bryan-thompson/inspector-assessment 1.37.0 → 1.38.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/cli/build/lib/assessment-runner/assessment-executor.js +29 -1
- package/cli/build/lib/assessment-runner/source-loader.js +11 -0
- package/cli/package.json +1 -1
- package/client/dist/assets/{OAuthCallback-6-wM7Zc1.js → OAuthCallback-AngeBaCl.js} +1 -1
- package/client/dist/assets/{OAuthDebugCallback-Bw9-AzzP.js → OAuthDebugCallback--FE6_fPs.js} +1 -1
- package/client/dist/assets/{index-DyCdQP10.js → index-BQC95Boo.js} +4 -4
- package/client/dist/index.html +1 -1
- package/client/lib/lib/assessment/coreTypes.d.ts +37 -0
- package/client/lib/lib/assessment/coreTypes.d.ts.map +1 -1
- package/client/lib/lib/assessment/resultTypes.d.ts +26 -1
- package/client/lib/lib/assessment/resultTypes.d.ts.map +1 -1
- package/client/lib/lib/securityPatterns/advancedExploitPatterns.d.ts +13 -0
- package/client/lib/lib/securityPatterns/advancedExploitPatterns.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/advancedExploitPatterns.js +504 -0
- package/client/lib/lib/securityPatterns/authSessionPatterns.d.ts +12 -0
- package/client/lib/lib/securityPatterns/authSessionPatterns.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/authSessionPatterns.js +357 -0
- package/client/lib/lib/securityPatterns/index.d.ts +18 -0
- package/client/lib/lib/securityPatterns/index.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/index.js +18 -0
- package/client/lib/lib/securityPatterns/injectionPatterns.d.ts +13 -0
- package/client/lib/lib/securityPatterns/injectionPatterns.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/injectionPatterns.js +356 -0
- package/client/lib/lib/securityPatterns/resourceExhaustionPatterns.d.ts +12 -0
- package/client/lib/lib/securityPatterns/resourceExhaustionPatterns.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/resourceExhaustionPatterns.js +215 -0
- package/client/lib/lib/securityPatterns/toolSpecificPatterns.d.ts +13 -0
- package/client/lib/lib/securityPatterns/toolSpecificPatterns.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/toolSpecificPatterns.js +373 -0
- package/client/lib/lib/securityPatterns/types.d.ts +20 -0
- package/client/lib/lib/securityPatterns/types.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/types.js +6 -0
- package/client/lib/lib/securityPatterns/utils.d.ts +56 -0
- package/client/lib/lib/securityPatterns/utils.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/utils.js +96 -0
- package/client/lib/lib/securityPatterns/validationPatterns.d.ts +13 -0
- package/client/lib/lib/securityPatterns/validationPatterns.d.ts.map +1 -0
- package/client/lib/lib/securityPatterns/validationPatterns.js +110 -0
- package/client/lib/lib/securityPatterns.d.ts +18 -69
- package/client/lib/lib/securityPatterns.d.ts.map +1 -1
- package/client/lib/lib/securityPatterns.js +18 -1946
- package/client/lib/services/assessment/AssessmentOrchestrator.d.ts +4 -1
- package/client/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -1
- package/client/lib/services/assessment/helpers/ExternalAPIDependencyDetector.d.ts +96 -5
- package/client/lib/services/assessment/helpers/ExternalAPIDependencyDetector.d.ts.map +1 -1
- package/client/lib/services/assessment/helpers/ExternalAPIDependencyDetector.js +202 -16
- package/client/lib/services/assessment/helpers/StdioTransportDetector.d.ts +137 -0
- package/client/lib/services/assessment/helpers/StdioTransportDetector.d.ts.map +1 -0
- package/client/lib/services/assessment/helpers/StdioTransportDetector.js +315 -0
- package/client/lib/services/assessment/helpers/ToolAnnotationExtractor.d.ts +34 -0
- package/client/lib/services/assessment/helpers/ToolAnnotationExtractor.d.ts.map +1 -0
- package/client/lib/services/assessment/helpers/ToolAnnotationExtractor.js +85 -0
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +17 -0
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/ErrorHandlingAssessor.js +162 -10
- package/client/lib/services/assessment/modules/ProtocolComplianceAssessor.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/ProtocolComplianceAssessor.js +30 -0
- package/client/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/SecurityAssessor.js +6 -0
- package/client/lib/services/assessment/modules/securityTests/AnnotationAwareSeverity.d.ts +55 -0
- package/client/lib/services/assessment/modules/securityTests/AnnotationAwareSeverity.d.ts.map +1 -0
- package/client/lib/services/assessment/modules/securityTests/AnnotationAwareSeverity.js +135 -0
- package/client/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts +6 -0
- package/client/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/securityTests/SafeResponseDetector.js +9 -1
- package/client/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts +20 -0
- package/client/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.js +37 -0
- package/client/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts +11 -1
- package/client/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/securityTests/SecurityPayloadTester.js +26 -1
- package/client/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts +1 -1
- package/client/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.js +10 -1
- package/client/lib/services/assessment/modules/securityTests/index.d.ts +1 -0
- package/client/lib/services/assessment/modules/securityTests/index.d.ts.map +1 -1
- package/client/lib/services/assessment/modules/securityTests/index.js +1 -0
- package/client/package.json +1 -1
- package/package.json +1 -1
- package/server/package.json +1 -1
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stdio Transport Detector
|
|
3
|
+
*
|
|
4
|
+
* Identifies stdio transport support from multiple sources:
|
|
5
|
+
* 1. server.json manifest (packages[0].transport.type)
|
|
6
|
+
* 2. package.json bin entries (indicates CLI/stdio)
|
|
7
|
+
* 3. Source code scanning for transport patterns
|
|
8
|
+
* 4. Runtime transport configuration
|
|
9
|
+
*
|
|
10
|
+
* This fixes Issue #172: C6/F6 incorrectly fails for valid stdio servers
|
|
11
|
+
* because transport detection previously relied solely on serverInfo metadata.
|
|
12
|
+
*
|
|
13
|
+
* @module helpers/StdioTransportDetector
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Detects transport capabilities from multiple sources.
|
|
17
|
+
*
|
|
18
|
+
* Detection priority (highest confidence first):
|
|
19
|
+
* 1. Runtime transport configuration (actual runtime proof)
|
|
20
|
+
* 2. server.json transport declaration (explicit manifest)
|
|
21
|
+
* 3. package.json bin entries (strong CLI/stdio indicator)
|
|
22
|
+
* 4. Source code patterns (StdioServerTransport, mcp.run, etc.)
|
|
23
|
+
*
|
|
24
|
+
* @public
|
|
25
|
+
*/
|
|
26
|
+
export class StdioTransportDetector {
|
|
27
|
+
/**
|
|
28
|
+
* TypeScript/JavaScript patterns for stdio transport
|
|
29
|
+
*/
|
|
30
|
+
STDIO_CODE_PATTERNS = [
|
|
31
|
+
{
|
|
32
|
+
pattern: /StdioServerTransport/,
|
|
33
|
+
description: "Uses StdioServerTransport class",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
pattern: /from\s*['"]@modelcontextprotocol\/sdk\/server\/stdio/,
|
|
37
|
+
description: "Imports MCP SDK stdio module",
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
pattern: /from\s*['"].*\/stdio/,
|
|
41
|
+
description: "Imports stdio transport module",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
pattern: /transport\s*[:=]\s*['"]stdio['"]/i,
|
|
45
|
+
description: "Declares transport as stdio",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
pattern: /createStdioTransport/,
|
|
49
|
+
description: "Creates stdio transport",
|
|
50
|
+
},
|
|
51
|
+
];
|
|
52
|
+
/**
|
|
53
|
+
* Python/FastMCP patterns for stdio transport
|
|
54
|
+
*/
|
|
55
|
+
PYTHON_STDIO_PATTERNS = [
|
|
56
|
+
{
|
|
57
|
+
pattern: /mcp\.run\s*\(\s*transport\s*=\s*['"]stdio['"]/,
|
|
58
|
+
description: "FastMCP run with stdio transport",
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
pattern: /StdioTransport/,
|
|
62
|
+
description: "Uses StdioTransport class",
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
pattern: /transport\s*=\s*['"]stdio['"]/i,
|
|
66
|
+
description: "Python stdio transport declaration",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
pattern: /from\s+mcp\.server\.stdio\s+import/,
|
|
70
|
+
description: "Imports MCP stdio module (Python)",
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
/**
|
|
74
|
+
* HTTP/SSE transport patterns
|
|
75
|
+
*/
|
|
76
|
+
HTTP_CODE_PATTERNS = [
|
|
77
|
+
{
|
|
78
|
+
pattern: /StreamableHTTPServerTransport/,
|
|
79
|
+
transport: "http",
|
|
80
|
+
description: "Uses StreamableHTTPServerTransport",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
pattern: /SSEServerTransport/,
|
|
84
|
+
transport: "sse",
|
|
85
|
+
description: "Uses SSEServerTransport",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
pattern: /transport\s*[:=]\s*['"]http['"]/i,
|
|
89
|
+
transport: "http",
|
|
90
|
+
description: "Declares transport as http",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
pattern: /transport\s*[:=]\s*['"]sse['"]/i,
|
|
94
|
+
transport: "sse",
|
|
95
|
+
description: "Declares transport as sse",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
pattern: /transport\s*[:=]\s*['"]streamable-http['"]/i,
|
|
99
|
+
transport: "http",
|
|
100
|
+
description: "Declares transport as streamable-http",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
pattern: /express|fastify|koa|hono/i,
|
|
104
|
+
transport: "http",
|
|
105
|
+
description: "Uses HTTP framework",
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
pattern: /app\.listen\s*\(/,
|
|
109
|
+
transport: "http",
|
|
110
|
+
description: "HTTP server listen call",
|
|
111
|
+
},
|
|
112
|
+
];
|
|
113
|
+
/**
|
|
114
|
+
* File patterns to skip during source code scanning
|
|
115
|
+
*/
|
|
116
|
+
SKIP_FILE_PATTERNS = [
|
|
117
|
+
/node_modules/i,
|
|
118
|
+
/\.test\.(ts|js|tsx|jsx|py)$/i,
|
|
119
|
+
/\.spec\.(ts|js|tsx|jsx|py)$/i,
|
|
120
|
+
/\.d\.ts$/i,
|
|
121
|
+
/package-lock\.json$/i,
|
|
122
|
+
/yarn\.lock$/i,
|
|
123
|
+
/\.map$/i,
|
|
124
|
+
/\.git\//i,
|
|
125
|
+
/dist\//i,
|
|
126
|
+
/build\//i,
|
|
127
|
+
/__tests__\//i,
|
|
128
|
+
/__mocks__\//i,
|
|
129
|
+
/__pycache__\//i,
|
|
130
|
+
/\.pytest_cache\//i,
|
|
131
|
+
];
|
|
132
|
+
/** Maximum file size for source scanning (500KB) */
|
|
133
|
+
MAX_FILE_SIZE = 500_000;
|
|
134
|
+
/**
|
|
135
|
+
* Detect transport capabilities from all available sources.
|
|
136
|
+
*
|
|
137
|
+
* @param sourceCodeFiles - Map of file paths to content
|
|
138
|
+
* @param packageJson - Parsed package.json content
|
|
139
|
+
* @param serverJson - Parsed server.json content
|
|
140
|
+
* @param runtimeTransport - Transport type from runtime config
|
|
141
|
+
* @returns Transport detection results
|
|
142
|
+
*/
|
|
143
|
+
detect(sourceCodeFiles, packageJson, serverJson, runtimeTransport) {
|
|
144
|
+
const evidence = [];
|
|
145
|
+
const detectedTransports = new Set();
|
|
146
|
+
// 1. Runtime transport config (highest confidence)
|
|
147
|
+
if (runtimeTransport) {
|
|
148
|
+
detectedTransports.add(runtimeTransport);
|
|
149
|
+
evidence.push({
|
|
150
|
+
source: "runtime-config",
|
|
151
|
+
transport: runtimeTransport,
|
|
152
|
+
confidence: "high",
|
|
153
|
+
detail: `Runtime transport configured as ${runtimeTransport}`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// 2. server.json transport declaration
|
|
157
|
+
if (serverJson?.packages?.[0]?.transport?.type) {
|
|
158
|
+
const transportType = serverJson.packages[0].transport
|
|
159
|
+
.type;
|
|
160
|
+
if (this.isValidTransport(transportType)) {
|
|
161
|
+
detectedTransports.add(transportType);
|
|
162
|
+
evidence.push({
|
|
163
|
+
source: "server.json",
|
|
164
|
+
transport: transportType,
|
|
165
|
+
confidence: "high",
|
|
166
|
+
detail: `server.json declares transport.type="${transportType}"`,
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
// 3. package.json bin entries (strong stdio indicator)
|
|
171
|
+
if (packageJson?.bin) {
|
|
172
|
+
const binEntry = typeof packageJson.bin === "string"
|
|
173
|
+
? packageJson.bin
|
|
174
|
+
: Object.keys(packageJson.bin)[0];
|
|
175
|
+
if (binEntry) {
|
|
176
|
+
detectedTransports.add("stdio");
|
|
177
|
+
evidence.push({
|
|
178
|
+
source: "package.json",
|
|
179
|
+
transport: "stdio",
|
|
180
|
+
confidence: "high",
|
|
181
|
+
detail: `package.json has bin entry (CLI tools use stdio)`,
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// 4. Source code scanning
|
|
186
|
+
const sourceCodeScanned = sourceCodeFiles !== undefined && sourceCodeFiles.size > 0;
|
|
187
|
+
if (sourceCodeFiles !== undefined && sourceCodeFiles.size > 0) {
|
|
188
|
+
const sourceEvidence = this.scanSourceCode(sourceCodeFiles);
|
|
189
|
+
for (const ev of sourceEvidence) {
|
|
190
|
+
evidence.push(ev);
|
|
191
|
+
detectedTransports.add(ev.transport);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
// Compute overall confidence
|
|
195
|
+
const confidence = this.computeConfidence(evidence);
|
|
196
|
+
return {
|
|
197
|
+
detectedTransports,
|
|
198
|
+
confidence,
|
|
199
|
+
evidence,
|
|
200
|
+
supportsStdio: detectedTransports.has("stdio"),
|
|
201
|
+
supportsHTTP: detectedTransports.has("http"),
|
|
202
|
+
supportsSSE: detectedTransports.has("sse"),
|
|
203
|
+
sourceCodeScanned,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Scan source code files for transport patterns.
|
|
208
|
+
*
|
|
209
|
+
* @param sourceCodeFiles - Map of file paths to content
|
|
210
|
+
* @returns Array of evidence from source code analysis
|
|
211
|
+
*/
|
|
212
|
+
scanSourceCode(sourceCodeFiles) {
|
|
213
|
+
const evidence = [];
|
|
214
|
+
const foundPatterns = new Set(); // Deduplicate
|
|
215
|
+
sourceCodeFiles.forEach((content, filePath) => {
|
|
216
|
+
// Skip test files, node_modules, etc.
|
|
217
|
+
if (this.shouldSkipFile(filePath))
|
|
218
|
+
return;
|
|
219
|
+
// Skip oversized files
|
|
220
|
+
if (content.length > this.MAX_FILE_SIZE)
|
|
221
|
+
return;
|
|
222
|
+
// Check stdio patterns (TypeScript/JavaScript)
|
|
223
|
+
for (const { pattern, description } of this.STDIO_CODE_PATTERNS) {
|
|
224
|
+
const key = `stdio:${description}`;
|
|
225
|
+
if (!foundPatterns.has(key) && pattern.test(content)) {
|
|
226
|
+
foundPatterns.add(key);
|
|
227
|
+
evidence.push({
|
|
228
|
+
source: "source-code",
|
|
229
|
+
transport: "stdio",
|
|
230
|
+
confidence: "medium",
|
|
231
|
+
detail: `${description} in ${this.shortenPath(filePath)}`,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
// Check stdio patterns (Python)
|
|
236
|
+
for (const { pattern, description } of this.PYTHON_STDIO_PATTERNS) {
|
|
237
|
+
const key = `stdio-py:${description}`;
|
|
238
|
+
if (!foundPatterns.has(key) && pattern.test(content)) {
|
|
239
|
+
foundPatterns.add(key);
|
|
240
|
+
evidence.push({
|
|
241
|
+
source: "source-code",
|
|
242
|
+
transport: "stdio",
|
|
243
|
+
confidence: "medium",
|
|
244
|
+
detail: `${description} in ${this.shortenPath(filePath)}`,
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Check HTTP/SSE patterns
|
|
249
|
+
for (const { pattern, transport, description } of this
|
|
250
|
+
.HTTP_CODE_PATTERNS) {
|
|
251
|
+
const key = `${transport}:${description}`;
|
|
252
|
+
if (!foundPatterns.has(key) && pattern.test(content)) {
|
|
253
|
+
foundPatterns.add(key);
|
|
254
|
+
evidence.push({
|
|
255
|
+
source: "source-code",
|
|
256
|
+
transport,
|
|
257
|
+
confidence: "medium",
|
|
258
|
+
detail: `${description} in ${this.shortenPath(filePath)}`,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
return evidence;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Check if a transport type is valid.
|
|
267
|
+
*/
|
|
268
|
+
isValidTransport(transport) {
|
|
269
|
+
return ["stdio", "http", "sse"].includes(transport);
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Check if a file should be skipped during scanning.
|
|
273
|
+
*/
|
|
274
|
+
shouldSkipFile(filePath) {
|
|
275
|
+
return this.SKIP_FILE_PATTERNS.some((pattern) => pattern.test(filePath));
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Shorten file path for display.
|
|
279
|
+
*/
|
|
280
|
+
shortenPath(filePath) {
|
|
281
|
+
const parts = filePath.split("/");
|
|
282
|
+
if (parts.length > 2) {
|
|
283
|
+
return `.../${parts.slice(-2).join("/")}`;
|
|
284
|
+
}
|
|
285
|
+
return filePath;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Compute overall confidence from collected evidence.
|
|
289
|
+
*
|
|
290
|
+
* Confidence rules:
|
|
291
|
+
* - High: Any high-confidence evidence present
|
|
292
|
+
* - Medium: Only medium-confidence evidence OR multiple sources agree
|
|
293
|
+
* - Low: No evidence or only weak patterns
|
|
294
|
+
*/
|
|
295
|
+
computeConfidence(evidence) {
|
|
296
|
+
if (evidence.length === 0) {
|
|
297
|
+
return "low";
|
|
298
|
+
}
|
|
299
|
+
// Any high-confidence evidence = overall high
|
|
300
|
+
if (evidence.some((e) => e.confidence === "high")) {
|
|
301
|
+
return "high";
|
|
302
|
+
}
|
|
303
|
+
// Multiple sources agreeing boosts confidence
|
|
304
|
+
const uniqueSources = new Set(evidence.map((e) => e.source));
|
|
305
|
+
if (uniqueSources.size >= 2) {
|
|
306
|
+
return "high";
|
|
307
|
+
}
|
|
308
|
+
// Multiple medium-confidence findings = overall medium
|
|
309
|
+
if (evidence.length >= 2) {
|
|
310
|
+
return "medium";
|
|
311
|
+
}
|
|
312
|
+
// Single medium-confidence finding
|
|
313
|
+
return "medium";
|
|
314
|
+
}
|
|
315
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Annotation Extractor
|
|
3
|
+
*
|
|
4
|
+
* Pre-extracts annotations from all tools for security assessment context.
|
|
5
|
+
* Issue #170: Enables annotation-aware security severity adjustment.
|
|
6
|
+
*
|
|
7
|
+
* This helper is used during context preparation to extract annotations
|
|
8
|
+
* BEFORE security testing begins, allowing SecurityAssessor to adjust
|
|
9
|
+
* vulnerability severity based on tool capabilities.
|
|
10
|
+
*
|
|
11
|
+
* @module helpers/ToolAnnotationExtractor
|
|
12
|
+
*/
|
|
13
|
+
import type { Tool } from "@modelcontextprotocol/sdk/types.js";
|
|
14
|
+
import type { ToolAnnotationsContext } from "../../../lib/assessment/coreTypes.js";
|
|
15
|
+
/**
|
|
16
|
+
* Extract tool annotations context from all tools.
|
|
17
|
+
*
|
|
18
|
+
* Iterates through all tools, extracts annotations using the existing
|
|
19
|
+
* 5-tier priority system, and computes server-level flags for read-only
|
|
20
|
+
* and closed-world servers.
|
|
21
|
+
*
|
|
22
|
+
* @param tools - Array of MCP tools to extract annotations from
|
|
23
|
+
* @returns ToolAnnotationsContext with per-tool annotations and server flags
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const context = extractToolAnnotationsContext(tools);
|
|
28
|
+
* if (context.serverIsReadOnly) {
|
|
29
|
+
* console.log("Server is 100% read-only");
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractToolAnnotationsContext(tools: Tool[]): ToolAnnotationsContext;
|
|
34
|
+
//# sourceMappingURL=ToolAnnotationExtractor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolAnnotationExtractor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/helpers/ToolAnnotationExtractor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,oCAAoC,CAAC;AAE/D,OAAO,KAAK,EACV,sBAAsB,EAEvB,MAAM,4BAA4B,CAAC;AAEpC;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,6BAA6B,CAC3C,KAAK,EAAE,IAAI,EAAE,GACZ,sBAAsB,CAkExB"}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool Annotation Extractor
|
|
3
|
+
*
|
|
4
|
+
* Pre-extracts annotations from all tools for security assessment context.
|
|
5
|
+
* Issue #170: Enables annotation-aware security severity adjustment.
|
|
6
|
+
*
|
|
7
|
+
* This helper is used during context preparation to extract annotations
|
|
8
|
+
* BEFORE security testing begins, allowing SecurityAssessor to adjust
|
|
9
|
+
* vulnerability severity based on tool capabilities.
|
|
10
|
+
*
|
|
11
|
+
* @module helpers/ToolAnnotationExtractor
|
|
12
|
+
*/
|
|
13
|
+
import { extractAnnotations } from "../modules/annotations/AlignmentChecker.js";
|
|
14
|
+
/**
|
|
15
|
+
* Extract tool annotations context from all tools.
|
|
16
|
+
*
|
|
17
|
+
* Iterates through all tools, extracts annotations using the existing
|
|
18
|
+
* 5-tier priority system, and computes server-level flags for read-only
|
|
19
|
+
* and closed-world servers.
|
|
20
|
+
*
|
|
21
|
+
* @param tools - Array of MCP tools to extract annotations from
|
|
22
|
+
* @returns ToolAnnotationsContext with per-tool annotations and server flags
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```typescript
|
|
26
|
+
* const context = extractToolAnnotationsContext(tools);
|
|
27
|
+
* if (context.serverIsReadOnly) {
|
|
28
|
+
* console.log("Server is 100% read-only");
|
|
29
|
+
* }
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
export function extractToolAnnotationsContext(tools) {
|
|
33
|
+
const toolAnnotations = new Map();
|
|
34
|
+
let readOnlyCount = 0;
|
|
35
|
+
let closedWorldCount = 0;
|
|
36
|
+
let annotatedCount = 0;
|
|
37
|
+
for (const tool of tools) {
|
|
38
|
+
// Use existing extraction logic with 5-tier priority
|
|
39
|
+
const extracted = extractAnnotations(tool);
|
|
40
|
+
// Validate extracted data has valid source
|
|
41
|
+
if (!extracted || !extracted.source) {
|
|
42
|
+
continue; // Skip tools with invalid extraction
|
|
43
|
+
}
|
|
44
|
+
// Convert to SecurityAnnotations (subset of ExtractedAnnotations)
|
|
45
|
+
// Ensure boolean fields are properly validated
|
|
46
|
+
const securityAnnotations = {
|
|
47
|
+
readOnlyHint: typeof extracted.readOnlyHint === "boolean"
|
|
48
|
+
? extracted.readOnlyHint
|
|
49
|
+
: undefined,
|
|
50
|
+
destructiveHint: typeof extracted.destructiveHint === "boolean"
|
|
51
|
+
? extracted.destructiveHint
|
|
52
|
+
: undefined,
|
|
53
|
+
idempotentHint: typeof extracted.idempotentHint === "boolean"
|
|
54
|
+
? extracted.idempotentHint
|
|
55
|
+
: undefined,
|
|
56
|
+
openWorldHint: typeof extracted.openWorldHint === "boolean"
|
|
57
|
+
? extracted.openWorldHint
|
|
58
|
+
: undefined,
|
|
59
|
+
source: extracted.source,
|
|
60
|
+
};
|
|
61
|
+
toolAnnotations.set(tool.name, securityAnnotations);
|
|
62
|
+
// Count tools with annotations
|
|
63
|
+
if (extracted.source !== "none") {
|
|
64
|
+
annotatedCount++;
|
|
65
|
+
// Count read-only tools
|
|
66
|
+
if (extracted.readOnlyHint === true) {
|
|
67
|
+
readOnlyCount++;
|
|
68
|
+
}
|
|
69
|
+
// Count closed-world tools
|
|
70
|
+
if (extracted.openWorldHint === false) {
|
|
71
|
+
closedWorldCount++;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const totalCount = tools.length;
|
|
76
|
+
return {
|
|
77
|
+
toolAnnotations,
|
|
78
|
+
// Server is read-only only if ALL annotated tools are read-only
|
|
79
|
+
serverIsReadOnly: annotatedCount > 0 && readOnlyCount === annotatedCount,
|
|
80
|
+
// Server is closed only if ALL annotated tools are closed
|
|
81
|
+
serverIsClosed: annotatedCount > 0 && closedWorldCount === annotatedCount,
|
|
82
|
+
annotatedToolCount: annotatedCount,
|
|
83
|
+
totalToolCount: totalCount,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
@@ -20,16 +20,22 @@ export declare class ErrorHandlingAssessor extends BaseAssessor {
|
|
|
20
20
|
private testExcessiveInput;
|
|
21
21
|
private getToolSchema;
|
|
22
22
|
private generateWrongTypeParams;
|
|
23
|
+
/**
|
|
24
|
+
* Issue #173: Return type for generateInvalidValueParams with metadata
|
|
25
|
+
* Tracks which parameter is being tested and whether it's required
|
|
26
|
+
*/
|
|
23
27
|
private generateInvalidValueParams;
|
|
24
28
|
private generateParamsWithValue;
|
|
25
29
|
/**
|
|
26
30
|
* Analyze invalid_values response to determine scoring impact
|
|
27
31
|
* Issue #99: Contextual empty string validation scoring
|
|
32
|
+
* Issue #173: Bonus points for suggestions and graceful degradation
|
|
28
33
|
*
|
|
29
34
|
* Classifications:
|
|
30
35
|
* - safe_rejection: Tool rejected with error (no penalty)
|
|
31
36
|
* - safe_reflection: Tool stored/echoed without executing (no penalty)
|
|
32
37
|
* - defensive_programming: Tool handled gracefully (no penalty)
|
|
38
|
+
* - graceful_degradation: Optional param handled with neutral response (no penalty + bonus)
|
|
33
39
|
* - execution_detected: Tool executed input (penalty)
|
|
34
40
|
* - unknown: Cannot determine (partial penalty)
|
|
35
41
|
*/
|
|
@@ -43,6 +49,17 @@ export declare class ErrorHandlingAssessor extends BaseAssessor {
|
|
|
43
49
|
* Examples: "Deleted 0 keys", "No results found", "Query returned 0"
|
|
44
50
|
*/
|
|
45
51
|
private isDefensiveProgrammingResponse;
|
|
52
|
+
/**
|
|
53
|
+
* Issue #173: Detect helpful suggestion patterns in error responses
|
|
54
|
+
* Patterns like: "Did you mean: Button, Checkbox?"
|
|
55
|
+
* Returns extracted suggestions for bonus scoring
|
|
56
|
+
*/
|
|
57
|
+
private detectSuggestionPatterns;
|
|
58
|
+
/**
|
|
59
|
+
* Issue #173: Check for neutral/graceful responses on optional parameters
|
|
60
|
+
* These indicate the tool handled empty/missing optional input appropriately
|
|
61
|
+
*/
|
|
62
|
+
private isNeutralGracefulResponse;
|
|
46
63
|
private calculateMetrics;
|
|
47
64
|
private determineErrorHandlingStatus;
|
|
48
65
|
private generateExplanation;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ErrorHandlingAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ErrorHandlingAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,uBAAuB,EAKxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAU9D,qBAAa,qBAAsB,SAAQ,YAAY;IACrD,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,eAAe,CAAkB;gBAE7B,MAAM,EAAE,uBAAuB;IAOrC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA6G1E,OAAO,CAAC,qBAAqB;YAuDf,qBAAqB;YAiCrB,qBAAqB;YA+IrB,cAAc;YA8Hd,iBAAiB;
|
|
1
|
+
{"version":3,"file":"ErrorHandlingAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ErrorHandlingAssessor.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,uBAAuB,EAKxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAU9D,qBAAa,qBAAsB,SAAQ,YAAY;IACrD,OAAO,CAAC,iBAAiB,CAA4B;IACrD,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,eAAe,CAAkB;gBAE7B,MAAM,EAAE,uBAAuB;IAOrC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA6G1E,OAAO,CAAC,qBAAqB;YAuDf,qBAAqB;YAiCrB,qBAAqB;YA+IrB,cAAc;YA8Hd,iBAAiB;YAyIjB,kBAAkB;IAwGhC,OAAO,CAAC,aAAa;IAOrB,OAAO,CAAC,uBAAuB;IAkC/B;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAkDlC,OAAO,CAAC,uBAAuB;IA4B/B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,4BAA4B;IAyFpC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAc/B;;;OAGG;IACH,OAAO,CAAC,8BAA8B;IAetC;;;;OAIG;IACH,OAAO,CAAC,wBAAwB;IAuChC;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAyBjC,OAAO,CAAC,gBAAgB;IAiJxB,OAAO,CAAC,4BAA4B;IAapC,OAAO,CAAC,mBAAmB;IAuE3B;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAgB9B,OAAO,CAAC,uBAAuB;CA4ChC"}
|