@bryan-thompson/inspector-assessment-client 1.26.5 → 1.26.7
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/dist/assets/{OAuthCallback-DpdInvWI.js → OAuthCallback-CCWVtjr7.js} +1 -1
- package/dist/assets/{OAuthDebugCallback-D1ImpKK5.js → OAuthDebugCallback-DqbXfUi4.js} +1 -1
- package/dist/assets/{index-umcoGmYw.js → index-CsDJSSWq.js} +4 -4
- package/dist/index.html +1 -1
- package/lib/lib/assessment/configTypes.d.ts +2 -0
- package/lib/lib/assessment/configTypes.d.ts.map +1 -1
- package/lib/lib/securityPatterns.d.ts +4 -2
- package/lib/lib/securityPatterns.d.ts.map +1 -1
- package/lib/lib/securityPatterns.js +146 -2
- package/lib/services/assessment/modules/AUPComplianceAssessor.js +9 -9
- package/lib/services/assessment/modules/AuthenticationAssessor.js +4 -4
- package/lib/services/assessment/modules/BaseAssessor.d.ts +0 -14
- package/lib/services/assessment/modules/BaseAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/BaseAssessor.js +1 -33
- package/lib/services/assessment/modules/CrossCapabilitySecurityAssessor.js +1 -1
- package/lib/services/assessment/modules/DeveloperExperienceAssessor.js +1 -1
- package/lib/services/assessment/modules/DocumentationAssessor.js +2 -2
- package/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ErrorHandlingAssessor.js +8 -8
- package/lib/services/assessment/modules/ExternalAPIScannerAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ExternalAPIScannerAssessor.js +3 -3
- package/lib/services/assessment/modules/FunctionalityAssessor.js +9 -9
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/MCPSpecComplianceAssessor.js +12 -12
- package/lib/services/assessment/modules/ManifestValidationAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ManifestValidationAssessor.js +9 -5
- package/lib/services/assessment/modules/PortabilityAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/PortabilityAssessor.js +3 -3
- package/lib/services/assessment/modules/ProhibitedLibrariesAssessor.js +4 -4
- package/lib/services/assessment/modules/PromptAssessor.js +2 -2
- package/lib/services/assessment/modules/ProtocolComplianceAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/ProtocolComplianceAssessor.js +7 -7
- package/lib/services/assessment/modules/ProtocolConformanceAssessor.js +1 -1
- package/lib/services/assessment/modules/ResourceAssessor.js +1 -1
- package/lib/services/assessment/modules/SecurityAssessor.d.ts +25 -2
- package/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/SecurityAssessor.js +149 -17
- package/lib/services/assessment/modules/TemporalAssessor.d.ts.map +1 -1
- package/lib/services/assessment/modules/TemporalAssessor.js +10 -10
- package/lib/services/assessment/modules/ToolAnnotationAssessor.js +9 -9
- package/lib/services/assessment/modules/UsabilityAssessor.js +1 -1
- package/lib/services/assessment/modules/annotations/DescriptionPoisoningDetector.d.ts.map +1 -1
- package/lib/services/assessment/modules/annotations/DescriptionPoisoningDetector.js +37 -0
- package/lib/services/assessment/modules/index.d.ts +3 -0
- package/lib/services/assessment/modules/index.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/ChainExecutionTester.d.ts +104 -0
- package/lib/services/assessment/modules/securityTests/ChainExecutionTester.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/ChainExecutionTester.js +257 -0
- package/lib/services/assessment/modules/securityTests/ConfidenceScorer.d.ts +57 -0
- package/lib/services/assessment/modules/securityTests/ConfidenceScorer.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/ConfidenceScorer.js +199 -0
- package/lib/services/assessment/modules/securityTests/CrossToolStateTester.d.ts +91 -0
- package/lib/services/assessment/modules/securityTests/CrossToolStateTester.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/CrossToolStateTester.js +225 -0
- package/lib/services/assessment/modules/securityTests/ErrorClassifier.d.ts +57 -0
- package/lib/services/assessment/modules/securityTests/ErrorClassifier.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/ErrorClassifier.js +113 -0
- package/lib/services/assessment/modules/securityTests/ExecutionArtifactDetector.d.ts +49 -0
- package/lib/services/assessment/modules/securityTests/ExecutionArtifactDetector.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/ExecutionArtifactDetector.js +74 -0
- package/lib/services/assessment/modules/securityTests/MathAnalyzer.d.ts +58 -0
- package/lib/services/assessment/modules/securityTests/MathAnalyzer.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/MathAnalyzer.js +251 -0
- package/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts +59 -0
- package/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/SafeResponseDetector.js +151 -0
- package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts +349 -0
- package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts.map +1 -0
- package/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.js +904 -0
- package/lib/services/assessment/modules/securityTests/SecurityPayloadGenerator.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/SecurityPayloadGenerator.js +49 -24
- package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts +122 -85
- package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.js +443 -1176
- package/lib/services/assessment/modules/securityTests/index.d.ts +3 -1
- package/lib/services/assessment/modules/securityTests/index.d.ts.map +1 -1
- package/lib/services/assessment/modules/securityTests/index.js +2 -0
- package/package.json +1 -1
|
@@ -0,0 +1,904 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Security Pattern Library
|
|
3
|
+
* Single source of truth for all regex patterns used in security analysis
|
|
4
|
+
*
|
|
5
|
+
* Extracted from SecurityResponseAnalyzer.ts (Issue #53)
|
|
6
|
+
* Consolidates 16 pattern collections, eliminates duplicates
|
|
7
|
+
*/
|
|
8
|
+
// =============================================================================
|
|
9
|
+
// HTTP ERROR PATTERNS (consolidated from 3 duplicate locations)
|
|
10
|
+
// =============================================================================
|
|
11
|
+
/**
|
|
12
|
+
* Patterns to detect HTTP error responses (4xx/5xx)
|
|
13
|
+
* Used by: isHttpErrorResponse(), analyzeComputedMathResult()
|
|
14
|
+
*/
|
|
15
|
+
export const HTTP_ERROR_PATTERNS = {
|
|
16
|
+
/** Full pattern: status code + context (e.g., "404 not found") */
|
|
17
|
+
statusWithContext: /\b(4\d{2}|5\d{2})\b.*?(not found|error|bad request|unauthorized|forbidden|internal server|unavailable|timeout|service)/i,
|
|
18
|
+
/** Simple pattern: status code at start (e.g., "404: ...") */
|
|
19
|
+
statusAtStart: /^(4\d{2}|5\d{2})[\s:]/,
|
|
20
|
+
/** Short "not found" responses */
|
|
21
|
+
notFound: /not found/i,
|
|
22
|
+
/** JSON status field pattern */
|
|
23
|
+
jsonStatus: /"status":\s*(4\d{2}|5\d{2})/,
|
|
24
|
+
};
|
|
25
|
+
// =============================================================================
|
|
26
|
+
// MCP VALIDATION ERROR PATTERNS
|
|
27
|
+
// =============================================================================
|
|
28
|
+
/**
|
|
29
|
+
* Patterns for MCP protocol validation errors
|
|
30
|
+
* These indicate proper input rejection (SAFE behavior)
|
|
31
|
+
* Used by: isMCPValidationError()
|
|
32
|
+
*/
|
|
33
|
+
export const VALIDATION_ERROR_PATTERNS = [
|
|
34
|
+
/parameter validation failed/i,
|
|
35
|
+
/schema validation (error|failed)/i,
|
|
36
|
+
/invalid (url|email|format|parameter|input|data)/i,
|
|
37
|
+
/must be a valid/i,
|
|
38
|
+
/must have a valid/i,
|
|
39
|
+
/failed to validate/i,
|
|
40
|
+
/validation error/i,
|
|
41
|
+
/does not match (pattern|schema)/i,
|
|
42
|
+
/not a valid (url|email|number|string)/i,
|
|
43
|
+
/expected.*but (got|received)/i,
|
|
44
|
+
/type mismatch/i,
|
|
45
|
+
/\brequired\b.*\bmissing\b/i,
|
|
46
|
+
/cannot.*be.*empty/i,
|
|
47
|
+
/must.*not.*be.*empty/i,
|
|
48
|
+
/empty.*not.*allowed/i,
|
|
49
|
+
/\brequired\b/i,
|
|
50
|
+
/missing.*required/i,
|
|
51
|
+
/field.*required/i,
|
|
52
|
+
];
|
|
53
|
+
// =============================================================================
|
|
54
|
+
// EXECUTION EVIDENCE PATTERNS
|
|
55
|
+
// =============================================================================
|
|
56
|
+
/**
|
|
57
|
+
* Patterns indicating actual code/command execution
|
|
58
|
+
* Used by: hasExecutionEvidence()
|
|
59
|
+
*/
|
|
60
|
+
export const EXECUTION_INDICATORS = [
|
|
61
|
+
/\bexecuted\b/i,
|
|
62
|
+
/\bprocessed\b/i,
|
|
63
|
+
/\bran\b.*command/i,
|
|
64
|
+
/\bcompleted\b/i,
|
|
65
|
+
/\bcomputed\b/i,
|
|
66
|
+
/\bcalculated\b/i,
|
|
67
|
+
/NullPointerException/i,
|
|
68
|
+
/SegmentationFault/i,
|
|
69
|
+
/StackOverflow/i,
|
|
70
|
+
/OutOfMemory/i,
|
|
71
|
+
/syntax error in executed/i,
|
|
72
|
+
/error while executing/i,
|
|
73
|
+
/failed during execution/i,
|
|
74
|
+
/error in query execution/i,
|
|
75
|
+
/runtime error/i,
|
|
76
|
+
/deleted \d+ (rows|files|records)/i,
|
|
77
|
+
/(file|resource) (opened|accessed|modified|deleted)/i,
|
|
78
|
+
/query returned \d+ results/i,
|
|
79
|
+
/modified \d+ records/i,
|
|
80
|
+
/\d+ rows affected/i,
|
|
81
|
+
/command output:/i,
|
|
82
|
+
/execution result:/i,
|
|
83
|
+
];
|
|
84
|
+
/**
|
|
85
|
+
* Patterns for detecting execution artifacts in response
|
|
86
|
+
* Used by: detectExecutionArtifacts()
|
|
87
|
+
*/
|
|
88
|
+
export const EXECUTION_ARTIFACT_PATTERNS = {
|
|
89
|
+
/** Always indicates execution */
|
|
90
|
+
alwaysExecution: [
|
|
91
|
+
/[a-z]+:x:\d+:\d+:/i, // passwd format
|
|
92
|
+
/uid=\d+\([^)]+\)\s+gid=\d+/i, // id command
|
|
93
|
+
/[d-][rwx-]{9}\s+\d+\s+[a-z]+/i, // ls -l format
|
|
94
|
+
/total\s+\d+\s*$/m, // ls total
|
|
95
|
+
/command_executed:\s*[^"\s]/i,
|
|
96
|
+
/stdout:\s*["']?[^"'\s]/i,
|
|
97
|
+
/(execution|output)_log:/i,
|
|
98
|
+
/\/bin\/(bash|sh|zsh|dash)/i,
|
|
99
|
+
/\b(root|administrator)\s*$/im,
|
|
100
|
+
/\/root\//i,
|
|
101
|
+
/PID:\s*\d{3,}/i,
|
|
102
|
+
],
|
|
103
|
+
/** Context-sensitive - only count if no echoed payload */
|
|
104
|
+
contextSensitive: [/\/etc\/passwd/i, /\/etc\/shadow/i, /file:\/\/\//i],
|
|
105
|
+
};
|
|
106
|
+
// =============================================================================
|
|
107
|
+
// CONNECTION ERROR PATTERNS (consolidated from 2 duplicate locations)
|
|
108
|
+
// =============================================================================
|
|
109
|
+
/**
|
|
110
|
+
* Patterns for connection/server errors
|
|
111
|
+
* Used by: isConnectionError(), isConnectionErrorFromException()
|
|
112
|
+
*/
|
|
113
|
+
export const CONNECTION_ERROR_PATTERNS = {
|
|
114
|
+
/** Unambiguous connection errors */
|
|
115
|
+
unambiguous: [
|
|
116
|
+
/MCP error -32001/i,
|
|
117
|
+
/MCP error -32603/i,
|
|
118
|
+
/MCP error -32000/i,
|
|
119
|
+
/MCP error -32700/i,
|
|
120
|
+
/socket hang up/i,
|
|
121
|
+
/ECONNREFUSED/i,
|
|
122
|
+
/ETIMEDOUT/i,
|
|
123
|
+
/network error/i,
|
|
124
|
+
/ERR_CONNECTION/i,
|
|
125
|
+
/fetch failed/i,
|
|
126
|
+
/connection reset/i,
|
|
127
|
+
/error POSTing to endpoint/i,
|
|
128
|
+
/error GETting.*endpoint/i,
|
|
129
|
+
/service unavailable/i,
|
|
130
|
+
/gateway timeout/i,
|
|
131
|
+
/unknown tool:/i,
|
|
132
|
+
/no such tool/i,
|
|
133
|
+
],
|
|
134
|
+
/** Only apply when response starts with MCP error prefix */
|
|
135
|
+
contextual: [
|
|
136
|
+
/bad request/i,
|
|
137
|
+
/unauthorized/i,
|
|
138
|
+
/forbidden/i,
|
|
139
|
+
/no valid session/i,
|
|
140
|
+
/session.*expired/i,
|
|
141
|
+
/internal server error/i,
|
|
142
|
+
/HTTP [45]\d\d/i,
|
|
143
|
+
],
|
|
144
|
+
/** MCP error prefix pattern */
|
|
145
|
+
mcpPrefix: /^mcp error -\d+:/i,
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Patterns for error classification
|
|
149
|
+
* Used by: classifyError(), classifyErrorFromException()
|
|
150
|
+
*/
|
|
151
|
+
export const ERROR_CLASSIFICATION_PATTERNS = {
|
|
152
|
+
connection: /socket|ECONNREFUSED|ETIMEDOUT|network|fetch failed|connection reset/i,
|
|
153
|
+
server: /-32603|-32000|-32700|internal server error|service unavailable|gateway timeout|HTTP 5\d\d|error POSTing.*endpoint|error GETting.*endpoint|bad request|HTTP 400|unauthorized|forbidden|no valid session|session.*expired/i,
|
|
154
|
+
protocol: /-32001/i,
|
|
155
|
+
};
|
|
156
|
+
// =============================================================================
|
|
157
|
+
// REFLECTION PATTERNS (safe response detection)
|
|
158
|
+
// =============================================================================
|
|
159
|
+
/**
|
|
160
|
+
* Status patterns indicating safe response handling
|
|
161
|
+
* Used by: isReflectionResponse()
|
|
162
|
+
*/
|
|
163
|
+
export const STATUS_PATTERNS = [
|
|
164
|
+
/\d+\s+total\s+(in\s+)?(memory|storage|items|results)/i,
|
|
165
|
+
/\d+\s+(results|items|records),?\s+\d+\s+total/i,
|
|
166
|
+
/action\s+executed\s+successfully:/i,
|
|
167
|
+
/command\s+executed\s+successfully:/i,
|
|
168
|
+
/"result":\s*"action\s+executed\s+successfully"/i,
|
|
169
|
+
/result.*action\s+executed\s+successfully/i,
|
|
170
|
+
/successfully\s+(executed|completed|processed):/i,
|
|
171
|
+
/successfully\s+(executed|completed|processed)"/i,
|
|
172
|
+
/action\s+received:/i,
|
|
173
|
+
/input\s+received:/i,
|
|
174
|
+
/request\s+received:/i,
|
|
175
|
+
/"safe"\s*:\s*true[^}]{0,500}("message"|"result"|"status"|"response")/i,
|
|
176
|
+
/("message"|"result"|"status"|"response")[^}]{0,500}"safe"\s*:\s*true/i,
|
|
177
|
+
/"vulnerable"\s*:\s*false[^}]{0,500}("safe"|"stored"|"reflected"|"status")/i,
|
|
178
|
+
/("safe"|"stored"|"reflected"|"status")[^}]{0,500}"vulnerable"\s*:\s*false/i,
|
|
179
|
+
/"status"\s*:\s*"acknowledged"[^}]{0,500}("message"|"result"|"safe")/i,
|
|
180
|
+
/("message"|"result"|"safe")[^}]{0,500}"status"\s*:\s*"acknowledged"/i,
|
|
181
|
+
];
|
|
182
|
+
/**
|
|
183
|
+
* Reflection patterns indicating safe data handling
|
|
184
|
+
* Used by: isReflectionResponse()
|
|
185
|
+
*/
|
|
186
|
+
export const REFLECTION_PATTERNS = [
|
|
187
|
+
// Storage patterns
|
|
188
|
+
/stored.*query/i,
|
|
189
|
+
/saved.*input/i,
|
|
190
|
+
/received.*parameter/i,
|
|
191
|
+
/processing.*request/i,
|
|
192
|
+
/storing.*data/i,
|
|
193
|
+
/added.*to.*collection/i,
|
|
194
|
+
// Echo patterns
|
|
195
|
+
/echo:/i,
|
|
196
|
+
/echoing/i,
|
|
197
|
+
/repeating/i,
|
|
198
|
+
/displaying/i,
|
|
199
|
+
/showing.*input/i,
|
|
200
|
+
/message.*echoed/i,
|
|
201
|
+
// Safe data handling
|
|
202
|
+
/safely.*as.*data/i,
|
|
203
|
+
/query.*stored/i,
|
|
204
|
+
/input.*saved/i,
|
|
205
|
+
/parameter.*received/i,
|
|
206
|
+
/command.*stored/i,
|
|
207
|
+
/stored.*command/i,
|
|
208
|
+
/data.*stored/i,
|
|
209
|
+
/stored.*data/i,
|
|
210
|
+
/action.*stored/i,
|
|
211
|
+
/stored.*action/i,
|
|
212
|
+
/text.*stored/i,
|
|
213
|
+
/stored.*text/i,
|
|
214
|
+
/setting.*stored/i,
|
|
215
|
+
/stored.*setting/i,
|
|
216
|
+
/instruction.*stored/i,
|
|
217
|
+
/stored.*instruction/i,
|
|
218
|
+
/url.*stored/i,
|
|
219
|
+
/stored.*url/i,
|
|
220
|
+
/package.*stored/i,
|
|
221
|
+
/stored.*package/i,
|
|
222
|
+
/stored.*safely/i,
|
|
223
|
+
/safely.*stored/i,
|
|
224
|
+
// Non-execution indicators
|
|
225
|
+
/without\s+execut/i,
|
|
226
|
+
/not\s+executed/i,
|
|
227
|
+
/never\s+executed/i,
|
|
228
|
+
/stored.*as.*data/i,
|
|
229
|
+
/treated.*as.*data/i,
|
|
230
|
+
/stored\s+in\s+(collection|database)/i,
|
|
231
|
+
/stored.*successfully/i,
|
|
232
|
+
/saved.*to/i,
|
|
233
|
+
/recorded\s+in/i,
|
|
234
|
+
/added\s+to/i,
|
|
235
|
+
// Processing status
|
|
236
|
+
/logged successfully:/i,
|
|
237
|
+
/queued for processing:/i,
|
|
238
|
+
/saved (for|successfully)/i,
|
|
239
|
+
/stored for (admin review|configuration|processing)/i,
|
|
240
|
+
/processed successfully/i,
|
|
241
|
+
/validated successfully/i,
|
|
242
|
+
/parsed successfully/i,
|
|
243
|
+
/(validation|processing) (passed|completed)/i,
|
|
244
|
+
// Error/rejection patterns (safe)
|
|
245
|
+
/error:.*not (found|in approved list|recognized)/i,
|
|
246
|
+
/error getting info for ['"].*['"]/i,
|
|
247
|
+
/invalid .* format.*stored as text/i,
|
|
248
|
+
/error:.*too (long|short|large)/i,
|
|
249
|
+
// Rate limiting / resource limits
|
|
250
|
+
/payload.?rejected/i,
|
|
251
|
+
/input.?exceeds.?limit/i,
|
|
252
|
+
/resource.?limit.?enforced/i,
|
|
253
|
+
/size.?limit/i,
|
|
254
|
+
/maximum.?length/i,
|
|
255
|
+
/rate.?limit/i,
|
|
256
|
+
/request.?throttled/i,
|
|
257
|
+
/input.?too.?large/i,
|
|
258
|
+
/exceeds.?maximum.?size/i,
|
|
259
|
+
/depth.?limit.?exceeded/i,
|
|
260
|
+
/nesting.?limit/i,
|
|
261
|
+
/complexity.?limit/i,
|
|
262
|
+
// Serialization safety
|
|
263
|
+
/serialization.?not.?supported/i,
|
|
264
|
+
/pickle.?disabled/i,
|
|
265
|
+
/deserialization.?blocked/i,
|
|
266
|
+
/unsafe.?format.?rejected/i,
|
|
267
|
+
/binary.?data.?not.?accepted/i,
|
|
268
|
+
/data.?stored.?safely/i,
|
|
269
|
+
/without.?deserialization/i,
|
|
270
|
+
/no.?pickle/i,
|
|
271
|
+
/stored.?without.?deserializ/i,
|
|
272
|
+
// Reference/sanitization indicators
|
|
273
|
+
/\[ref-[a-f0-9]+\]/i,
|
|
274
|
+
/stored.*\[ref-/i,
|
|
275
|
+
/\[sanitized\]/i,
|
|
276
|
+
/\[redacted\]/i,
|
|
277
|
+
/\[filtered\]/i,
|
|
278
|
+
/\[blocked\]/i,
|
|
279
|
+
/expression.*stored:/i,
|
|
280
|
+
/input.*sanitized/i,
|
|
281
|
+
/content.*replaced/i,
|
|
282
|
+
];
|
|
283
|
+
// =============================================================================
|
|
284
|
+
// AUTH BYPASS PATTERNS (Issue #75, CVE-2025-52882)
|
|
285
|
+
// =============================================================================
|
|
286
|
+
/**
|
|
287
|
+
* Fail-open authentication patterns (VULNERABLE)
|
|
288
|
+
* Used by: analyzeAuthBypassResponse()
|
|
289
|
+
*/
|
|
290
|
+
export const AUTH_FAIL_OPEN_PATTERNS = [
|
|
291
|
+
{
|
|
292
|
+
pattern: /"auth_type"\s*:\s*"fail-open"/i,
|
|
293
|
+
evidence: "auth_type: fail-open (CVE-2025-52882)",
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
pattern: /"auth_status"\s*:\s*"bypassed"/i,
|
|
297
|
+
evidence: "auth_status: bypassed",
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
pattern: /access.*granted.*despite/i,
|
|
301
|
+
evidence: "access granted despite failure",
|
|
302
|
+
},
|
|
303
|
+
{ pattern: /authentication.*skipped/i, evidence: "authentication skipped" },
|
|
304
|
+
{ pattern: /fail[\s-]?open/i, evidence: "fail-open pattern detected" },
|
|
305
|
+
{ pattern: /bypassed.*auth/i, evidence: "auth bypassed" },
|
|
306
|
+
{ pattern: /authentication.*bypassed/i, evidence: "authentication bypassed" },
|
|
307
|
+
{
|
|
308
|
+
pattern: /"vulnerable"\s*:\s*true[^}]*(?:"auth_status"|"auth_type"|"auth_error")|(?:"auth_status"|"auth_type"|"auth_error")[^}]*"vulnerable"\s*:\s*true/i,
|
|
309
|
+
evidence: "vulnerable flag with auth context",
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
pattern: /auth.*succeeded.*null/i,
|
|
313
|
+
evidence: "auth succeeded with null token",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
pattern: /granted.*without.*valid/i,
|
|
317
|
+
evidence: "granted without valid token",
|
|
318
|
+
},
|
|
319
|
+
{ pattern: /"action_performed"/i, evidence: "action performed indicator" },
|
|
320
|
+
];
|
|
321
|
+
/**
|
|
322
|
+
* Fail-closed authentication patterns (SAFE)
|
|
323
|
+
* Used by: analyzeAuthBypassResponse()
|
|
324
|
+
*/
|
|
325
|
+
export const AUTH_FAIL_CLOSED_PATTERNS = [
|
|
326
|
+
{
|
|
327
|
+
pattern: /"auth_type"\s*:\s*"fail-closed"/i,
|
|
328
|
+
evidence: "auth_type: fail-closed (secure)",
|
|
329
|
+
},
|
|
330
|
+
{ pattern: /"auth_status"\s*:\s*"denied"/i, evidence: "auth_status: denied" },
|
|
331
|
+
{ pattern: /access.*denied/i, evidence: "access denied" },
|
|
332
|
+
{ pattern: /authentication.*failed/i, evidence: "authentication failed" },
|
|
333
|
+
{ pattern: /fail[\s-]?closed/i, evidence: "fail-closed pattern detected" },
|
|
334
|
+
{ pattern: /"status"\s*:\s*"blocked"/i, evidence: "status: blocked" },
|
|
335
|
+
{ pattern: /invalid.*token/i, evidence: "invalid token rejection" },
|
|
336
|
+
{ pattern: /token.*required/i, evidence: "token required" },
|
|
337
|
+
{ pattern: /unauthorized/i, evidence: "unauthorized response" },
|
|
338
|
+
{ pattern: /"denial_reason"/i, evidence: "denial reason provided" },
|
|
339
|
+
];
|
|
340
|
+
// =============================================================================
|
|
341
|
+
// CROSS-TOOL STATE-BASED AUTH PATTERNS (Issue #92, Challenge #7)
|
|
342
|
+
// =============================================================================
|
|
343
|
+
/**
|
|
344
|
+
* Patterns indicating vulnerable shared state authorization
|
|
345
|
+
* Detects cross-tool privilege escalation via shared mutable state
|
|
346
|
+
* Used by: analyzeStateBasedAuthBypass()
|
|
347
|
+
*/
|
|
348
|
+
export const STATE_AUTH_VULNERABLE_PATTERNS = [
|
|
349
|
+
{
|
|
350
|
+
pattern: /"admin_mode"\s*:\s*true/i,
|
|
351
|
+
evidence: "admin_mode enabled in response",
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
pattern: /hint.*use\s+config_modifier/i,
|
|
355
|
+
evidence: "Tool hints at cross-tool state dependency",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
pattern: /admin_mode.*set\s+by.*another\s+tool/i,
|
|
359
|
+
evidence: "Explicit cross-tool state dependency",
|
|
360
|
+
},
|
|
361
|
+
{
|
|
362
|
+
pattern: /"evidence".*cross-tool.*privilege/i,
|
|
363
|
+
evidence: "Cross-tool privilege escalation detected",
|
|
364
|
+
},
|
|
365
|
+
{
|
|
366
|
+
pattern: /elevated\s+privileges?\s+granted/i,
|
|
367
|
+
evidence: "Elevated privileges granted",
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
pattern: /admin\s+mode\s+activated/i,
|
|
371
|
+
evidence: "Admin mode activated (state modifier)",
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
pattern: /"hint".*config_modifier.*admin_mode/i,
|
|
375
|
+
evidence: "Response hints at config_modifier for admin_mode",
|
|
376
|
+
},
|
|
377
|
+
{
|
|
378
|
+
pattern: /Use\s+config_modifier.*enable.*admin_mode/i,
|
|
379
|
+
evidence: "Tool depends on config_modifier for authorization",
|
|
380
|
+
},
|
|
381
|
+
];
|
|
382
|
+
/**
|
|
383
|
+
* Patterns indicating safe independent authorization
|
|
384
|
+
* Detects tools that use per-request authentication (secure)
|
|
385
|
+
* Used by: analyzeStateBasedAuthBypass()
|
|
386
|
+
*/
|
|
387
|
+
export const STATE_AUTH_SAFE_PATTERNS = [
|
|
388
|
+
{
|
|
389
|
+
pattern: /"shared_state_checked"\s*:\s*false/i,
|
|
390
|
+
evidence: "Tool explicitly states it doesn't use shared state",
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
pattern: /"independent_auth_required"\s*:\s*true/i,
|
|
394
|
+
evidence: "Tool requires independent per-request auth",
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
pattern: /requires\s+independent\s+authorization/i,
|
|
398
|
+
evidence: "Independent authorization required",
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
pattern: /(?:not|does\s+not|doesn't)\s+(?:use\s+)?shared\s+state/i,
|
|
402
|
+
evidence: "Tool confirms it does not use shared state",
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
pattern: /stored.*for.*admin.*review/i,
|
|
406
|
+
evidence: "Request stored for admin review (no auto-execution)",
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
pattern: /per-request\s+auth/i,
|
|
410
|
+
evidence: "Per-request authentication enforced",
|
|
411
|
+
},
|
|
412
|
+
];
|
|
413
|
+
/**
|
|
414
|
+
* Patterns indicating vulnerable chain execution behavior
|
|
415
|
+
* - Arbitrary tool invocation without allowlist
|
|
416
|
+
* - Output injection via template substitution
|
|
417
|
+
* - Recursive/circular chain execution
|
|
418
|
+
* - Missing depth limits
|
|
419
|
+
* - State poisoning between steps
|
|
420
|
+
*
|
|
421
|
+
* Used by: analyzeChainExploitation()
|
|
422
|
+
*/
|
|
423
|
+
export const CHAIN_EXPLOIT_VULNERABLE_PATTERNS = [
|
|
424
|
+
// Chain execution evidence
|
|
425
|
+
{
|
|
426
|
+
pattern: /chain_results/i,
|
|
427
|
+
weight: 0.9,
|
|
428
|
+
category: "chain_execution",
|
|
429
|
+
description: "Chain execution returning step results",
|
|
430
|
+
},
|
|
431
|
+
{
|
|
432
|
+
pattern: /steps_executed/i,
|
|
433
|
+
weight: 0.8,
|
|
434
|
+
category: "chain_execution",
|
|
435
|
+
description: "Steps executed counter in response",
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
pattern: /vulnerabilities_triggered/i,
|
|
439
|
+
weight: 1.0,
|
|
440
|
+
category: "chain_execution",
|
|
441
|
+
description: "Explicit vulnerabilities triggered indicator",
|
|
442
|
+
},
|
|
443
|
+
// Output injection evidence
|
|
444
|
+
{
|
|
445
|
+
pattern: /output_injection/i,
|
|
446
|
+
weight: 1.0,
|
|
447
|
+
category: "output_injection",
|
|
448
|
+
description: "Output injection between chain steps",
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
pattern: /\{\{output\}\}.*substitut/i,
|
|
452
|
+
weight: 0.9,
|
|
453
|
+
category: "output_injection",
|
|
454
|
+
description: "Template output substitution performed",
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
pattern: /last_output.*passed/i,
|
|
458
|
+
weight: 0.8,
|
|
459
|
+
category: "output_injection",
|
|
460
|
+
description: "Raw output passed to next step",
|
|
461
|
+
},
|
|
462
|
+
// Recursive chain evidence
|
|
463
|
+
{
|
|
464
|
+
pattern: /recursive_chain/i,
|
|
465
|
+
weight: 1.0,
|
|
466
|
+
category: "recursive_chain",
|
|
467
|
+
description: "Self-referential chain execution",
|
|
468
|
+
},
|
|
469
|
+
{
|
|
470
|
+
pattern: /chain_executor.*within.*chain/i,
|
|
471
|
+
weight: 0.9,
|
|
472
|
+
category: "recursive_chain",
|
|
473
|
+
description: "Chain executor called recursively",
|
|
474
|
+
},
|
|
475
|
+
{
|
|
476
|
+
pattern: /circular.*chain/i,
|
|
477
|
+
weight: 0.9,
|
|
478
|
+
category: "recursive_chain",
|
|
479
|
+
description: "Circular chain reference detected",
|
|
480
|
+
},
|
|
481
|
+
// Arbitrary tool acceptance
|
|
482
|
+
{
|
|
483
|
+
pattern: /arbitrary.*tool.*step/i,
|
|
484
|
+
weight: 0.9,
|
|
485
|
+
category: "arbitrary_tool",
|
|
486
|
+
description: "Arbitrary tool name accepted in chain",
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
pattern: /unknown.*tool.*executed/i,
|
|
490
|
+
weight: 0.8,
|
|
491
|
+
category: "arbitrary_tool",
|
|
492
|
+
description: "Unknown tool executed without validation",
|
|
493
|
+
},
|
|
494
|
+
{
|
|
495
|
+
pattern: /attempted.*execute.*unknown/i,
|
|
496
|
+
weight: 0.8,
|
|
497
|
+
category: "arbitrary_tool",
|
|
498
|
+
description: "Attempted execution of unknown tool",
|
|
499
|
+
},
|
|
500
|
+
// Shadowed tool execution
|
|
501
|
+
{
|
|
502
|
+
pattern: /shadowed.*tool/i,
|
|
503
|
+
weight: 1.0,
|
|
504
|
+
category: "tool_shadowing",
|
|
505
|
+
description: "Shadowed/poisoned tool executed",
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
pattern: /shadowed_definition/i,
|
|
509
|
+
weight: 0.9,
|
|
510
|
+
category: "tool_shadowing",
|
|
511
|
+
description: "Shadowed definition used instead of original",
|
|
512
|
+
},
|
|
513
|
+
];
|
|
514
|
+
/**
|
|
515
|
+
* Patterns indicating safe/hardened chain handling
|
|
516
|
+
* - Tool allowlist validation
|
|
517
|
+
* - No execution (validation only)
|
|
518
|
+
* - Depth limits enforced
|
|
519
|
+
* - Output injection blocked
|
|
520
|
+
*
|
|
521
|
+
* Used by: analyzeChainExploitation()
|
|
522
|
+
*/
|
|
523
|
+
// =============================================================================
|
|
524
|
+
// CHAIN VULNERABILITY THRESHOLDS (Issue #93)
|
|
525
|
+
// =============================================================================
|
|
526
|
+
/**
|
|
527
|
+
* Threshold for confirming vulnerable chain execution behavior.
|
|
528
|
+
* Value of 1.5 requires ~2 weighted pattern matches to confirm vulnerability.
|
|
529
|
+
*
|
|
530
|
+
* Derived from A/B testing against vulnerable-mcp/hardened-mcp testbed:
|
|
531
|
+
* - vulnerable-mcp: typical scores 2.0-4.0 for vulnerable chains
|
|
532
|
+
* - hardened-mcp: typical scores 0.0-0.8 for safe chains
|
|
533
|
+
*
|
|
534
|
+
* Setting at 1.5 provides margin against false positives while
|
|
535
|
+
* maintaining detection of genuine vulnerabilities.
|
|
536
|
+
*/
|
|
537
|
+
export const CHAIN_VULNERABLE_THRESHOLD = 1.5;
|
|
538
|
+
/**
|
|
539
|
+
* Threshold for confirming safe/hardened chain behavior.
|
|
540
|
+
* Value of 1.0 requires 1+ weighted safe pattern matches.
|
|
541
|
+
*
|
|
542
|
+
* Derived from A/B testing:
|
|
543
|
+
* - hardened-mcp: typical scores 1.5-3.0 for safe chains
|
|
544
|
+
* - vulnerable-mcp: typical scores 0.0-0.5 for safe patterns
|
|
545
|
+
*/
|
|
546
|
+
export const CHAIN_SAFE_THRESHOLD = 1.0;
|
|
547
|
+
// =============================================================================
|
|
548
|
+
// CHAIN VULNERABILITY CATEGORY PATTERNS (Issue #93)
|
|
549
|
+
// =============================================================================
|
|
550
|
+
/**
|
|
551
|
+
* Maps vulnerability categories to detection patterns.
|
|
552
|
+
* Used by analyzeChainExploitation() for category classification.
|
|
553
|
+
*
|
|
554
|
+
* Extracted from inline patterns to maintain single source of truth.
|
|
555
|
+
*/
|
|
556
|
+
export const CHAIN_CATEGORY_PATTERNS = {
|
|
557
|
+
OUTPUT_INJECTION: [
|
|
558
|
+
{ pattern: /output_injection/i, category: "OUTPUT_INJECTION" },
|
|
559
|
+
{ pattern: /\{\{output\}\}.*substitut/i, category: "OUTPUT_INJECTION" },
|
|
560
|
+
],
|
|
561
|
+
RECURSIVE_CHAIN: [
|
|
562
|
+
{ pattern: /recursive_chain/i, category: "RECURSIVE_CHAIN" },
|
|
563
|
+
{ pattern: /chain_executor.*within/i, category: "RECURSIVE_CHAIN" },
|
|
564
|
+
],
|
|
565
|
+
ARBITRARY_TOOL_INVOCATION: [
|
|
566
|
+
{ pattern: /arbitrary.*tool/i, category: "ARBITRARY_TOOL_INVOCATION" },
|
|
567
|
+
{
|
|
568
|
+
pattern: /unknown.*tool.*executed/i,
|
|
569
|
+
category: "ARBITRARY_TOOL_INVOCATION",
|
|
570
|
+
},
|
|
571
|
+
],
|
|
572
|
+
TOOL_SHADOWING: [
|
|
573
|
+
{ pattern: /shadowed.*tool/i, category: "TOOL_SHADOWING" },
|
|
574
|
+
{ pattern: /shadowed_definition/i, category: "TOOL_SHADOWING" },
|
|
575
|
+
],
|
|
576
|
+
MISSING_DEPTH_LIMIT: [
|
|
577
|
+
{
|
|
578
|
+
pattern: /steps_executed.*[1-9][0-9]/i,
|
|
579
|
+
category: "MISSING_DEPTH_LIMIT",
|
|
580
|
+
},
|
|
581
|
+
{ pattern: /no.*depth.*limit/i, category: "MISSING_DEPTH_LIMIT" },
|
|
582
|
+
],
|
|
583
|
+
STATE_POISONING: [
|
|
584
|
+
{ pattern: /state.*poison/i, category: "STATE_POISONING" },
|
|
585
|
+
{ pattern: /config.*modified.*chain/i, category: "STATE_POISONING" },
|
|
586
|
+
],
|
|
587
|
+
};
|
|
588
|
+
/**
|
|
589
|
+
* Detect vulnerability categories from response text.
|
|
590
|
+
* Returns array of detected category names.
|
|
591
|
+
*/
|
|
592
|
+
export function detectVulnerabilityCategories(responseText) {
|
|
593
|
+
const categories = [];
|
|
594
|
+
for (const [categoryName, patterns] of Object.entries(CHAIN_CATEGORY_PATTERNS)) {
|
|
595
|
+
for (const { pattern } of patterns) {
|
|
596
|
+
if (pattern.test(responseText)) {
|
|
597
|
+
if (!categories.includes(categoryName)) {
|
|
598
|
+
categories.push(categoryName);
|
|
599
|
+
}
|
|
600
|
+
break; // Found match for this category, move to next
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return categories;
|
|
605
|
+
}
|
|
606
|
+
export const CHAIN_EXPLOIT_SAFE_PATTERNS = [
|
|
607
|
+
// Validation-only behavior
|
|
608
|
+
{
|
|
609
|
+
pattern: /stored.*for.*review/i,
|
|
610
|
+
weight: 0.8,
|
|
611
|
+
category: "safe_storage",
|
|
612
|
+
description: "Chain stored for review, not executed",
|
|
613
|
+
},
|
|
614
|
+
{
|
|
615
|
+
pattern: /validation.*only/i,
|
|
616
|
+
weight: 0.9,
|
|
617
|
+
category: "safe_validation",
|
|
618
|
+
description: "Chain validated but not executed",
|
|
619
|
+
},
|
|
620
|
+
{
|
|
621
|
+
pattern: /chain.*validated/i,
|
|
622
|
+
weight: 0.7,
|
|
623
|
+
category: "safe_validation",
|
|
624
|
+
description: "Chain validation response",
|
|
625
|
+
},
|
|
626
|
+
{
|
|
627
|
+
pattern: /pending.*review/i,
|
|
628
|
+
weight: 0.8,
|
|
629
|
+
category: "safe_storage",
|
|
630
|
+
description: "Request pending admin review",
|
|
631
|
+
},
|
|
632
|
+
// Allowlist enforcement
|
|
633
|
+
{
|
|
634
|
+
pattern: /tool.*not.*in.*allowlist/i,
|
|
635
|
+
weight: 0.9,
|
|
636
|
+
category: "allowlist",
|
|
637
|
+
description: "Tool rejected - not in allowlist",
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
pattern: /only.*safe.*tools.*permitted/i,
|
|
641
|
+
weight: 0.9,
|
|
642
|
+
category: "allowlist",
|
|
643
|
+
description: "Allowlist enforcement message",
|
|
644
|
+
},
|
|
645
|
+
{
|
|
646
|
+
pattern: /blocked.*tool.*chain/i,
|
|
647
|
+
weight: 0.8,
|
|
648
|
+
category: "allowlist",
|
|
649
|
+
description: "Tool blocked from chain execution",
|
|
650
|
+
},
|
|
651
|
+
// Depth limit enforcement
|
|
652
|
+
{
|
|
653
|
+
pattern: /depth.*limit.*enforced/i,
|
|
654
|
+
weight: 0.8,
|
|
655
|
+
category: "depth_limit",
|
|
656
|
+
description: "Depth limit properly enforced",
|
|
657
|
+
},
|
|
658
|
+
{
|
|
659
|
+
pattern: /max.*depth.*exceeded/i,
|
|
660
|
+
weight: 0.7,
|
|
661
|
+
category: "depth_limit",
|
|
662
|
+
description: "Chain rejected for exceeding depth",
|
|
663
|
+
},
|
|
664
|
+
// No execution indicators
|
|
665
|
+
{
|
|
666
|
+
pattern: /chain_executed.*false/i,
|
|
667
|
+
weight: 0.9,
|
|
668
|
+
category: "no_execution",
|
|
669
|
+
description: "Chain execution disabled",
|
|
670
|
+
},
|
|
671
|
+
{
|
|
672
|
+
pattern: /execution.*disabled/i,
|
|
673
|
+
weight: 0.8,
|
|
674
|
+
category: "no_execution",
|
|
675
|
+
description: "Execution capability disabled",
|
|
676
|
+
},
|
|
677
|
+
];
|
|
678
|
+
// =============================================================================
|
|
679
|
+
// SEARCH/RETRIEVAL PATTERNS
|
|
680
|
+
// =============================================================================
|
|
681
|
+
/**
|
|
682
|
+
* Patterns indicating search result responses
|
|
683
|
+
* Used by: isSearchResultResponse()
|
|
684
|
+
*/
|
|
685
|
+
export const SEARCH_RESULT_PATTERNS = [
|
|
686
|
+
/"results"\s*:\s*\[/i,
|
|
687
|
+
/"type"\s*:\s*"search"/i,
|
|
688
|
+
/"object"\s*:\s*"list"/i,
|
|
689
|
+
/\bhighlight\b/i,
|
|
690
|
+
/search\s+results/i,
|
|
691
|
+
/found\s+\d+\s+(results?|pages?|items?)/i,
|
|
692
|
+
/query\s+(returned|matched)/i,
|
|
693
|
+
/\d+\s+(results?|matches?|hits?)\s+for/i,
|
|
694
|
+
/"has_more"\s*:/i,
|
|
695
|
+
/next_cursor/i,
|
|
696
|
+
];
|
|
697
|
+
/**
|
|
698
|
+
* Patterns indicating creation/modification responses
|
|
699
|
+
* Used by: isCreationResponse()
|
|
700
|
+
*/
|
|
701
|
+
export const CREATION_PATTERNS = [
|
|
702
|
+
/successfully\s+created/i,
|
|
703
|
+
/database\s+created/i,
|
|
704
|
+
/page\s+created/i,
|
|
705
|
+
/resource\s+created/i,
|
|
706
|
+
/\bcreate\s+table\b/i,
|
|
707
|
+
/\binsert\s+into\b/i,
|
|
708
|
+
/"id"\s*:\s*"[a-f0-9-]{36}"/i,
|
|
709
|
+
/"object"\s*:\s*"(page|database)"/i,
|
|
710
|
+
/collection:\/\//i,
|
|
711
|
+
/successfully\s+(added|inserted|updated|modified)/i,
|
|
712
|
+
/resource\s+id:\s*[a-f0-9-]/i,
|
|
713
|
+
/"created_time"/i,
|
|
714
|
+
/"last_edited_time"/i,
|
|
715
|
+
];
|
|
716
|
+
// =============================================================================
|
|
717
|
+
// INJECTION DETECTION PATTERNS
|
|
718
|
+
// =============================================================================
|
|
719
|
+
/**
|
|
720
|
+
* Patterns for echoed injection payloads
|
|
721
|
+
* Used by: containsEchoedInjectionPayload()
|
|
722
|
+
*/
|
|
723
|
+
export const ECHOED_PAYLOAD_PATTERNS = [
|
|
724
|
+
/<!DOCTYPE\s+\w+\s+\[/i,
|
|
725
|
+
/<!ENTITY\s+\w+\s+SYSTEM/i,
|
|
726
|
+
/<!ENTITY\s+%\s*\w+/i,
|
|
727
|
+
/stored.*http:\/\//i,
|
|
728
|
+
/saved.*http:\/\//i,
|
|
729
|
+
/stored.*union\s+select/i,
|
|
730
|
+
/stored.*drop\s+table/i,
|
|
731
|
+
/stored\s+query:\s*[<'"]/i,
|
|
732
|
+
/saved\s+data:\s*[<'"]/i,
|
|
733
|
+
];
|
|
734
|
+
/**
|
|
735
|
+
* Fallback execution detection patterns
|
|
736
|
+
* Used by: analyzeInjectionResponse()
|
|
737
|
+
*/
|
|
738
|
+
export const FALLBACK_EXECUTION_PATTERNS = [
|
|
739
|
+
/executed/i,
|
|
740
|
+
/command.*ran/i,
|
|
741
|
+
/result.*is/i,
|
|
742
|
+
/output.*:/i,
|
|
743
|
+
/returned.*value/i,
|
|
744
|
+
];
|
|
745
|
+
// =============================================================================
|
|
746
|
+
// VALIDATION/REJECTION PATTERNS
|
|
747
|
+
// =============================================================================
|
|
748
|
+
/**
|
|
749
|
+
* Text-based validation rejection patterns
|
|
750
|
+
* Used by: isValidationRejection()
|
|
751
|
+
*/
|
|
752
|
+
export const TEXT_REJECTION_PATTERNS = [
|
|
753
|
+
/validation failed/i,
|
|
754
|
+
/rejected/i,
|
|
755
|
+
/not.*approved/i,
|
|
756
|
+
/not.*in.*list/i,
|
|
757
|
+
/invalid.*input/i,
|
|
758
|
+
/error:.*invalid/i,
|
|
759
|
+
];
|
|
760
|
+
/**
|
|
761
|
+
* Result field rejection patterns (for JSON responses)
|
|
762
|
+
* Used by: isValidationRejection()
|
|
763
|
+
*/
|
|
764
|
+
export const RESULT_REJECTION_PATTERNS = [
|
|
765
|
+
/validation (failed|error)/i,
|
|
766
|
+
/rejected/i,
|
|
767
|
+
/not.*approved/i,
|
|
768
|
+
/not.*in.*list/i,
|
|
769
|
+
/invalid.*input/i,
|
|
770
|
+
/error:.*invalid/i,
|
|
771
|
+
];
|
|
772
|
+
/**
|
|
773
|
+
* Ambiguous validation pattern strings (for confidence calculation)
|
|
774
|
+
* Used by: isValidationPattern()
|
|
775
|
+
*/
|
|
776
|
+
export const AMBIGUOUS_VALIDATION_PATTERNS = [
|
|
777
|
+
"type.*error",
|
|
778
|
+
"invalid.*type",
|
|
779
|
+
"error",
|
|
780
|
+
"invalid",
|
|
781
|
+
"failed",
|
|
782
|
+
"negative.*not.*allowed",
|
|
783
|
+
"must.*be.*positive",
|
|
784
|
+
"invalid.*value",
|
|
785
|
+
"overflow",
|
|
786
|
+
"out.*of.*range",
|
|
787
|
+
];
|
|
788
|
+
// =============================================================================
|
|
789
|
+
// TOOL CLASSIFICATION PATTERNS
|
|
790
|
+
// =============================================================================
|
|
791
|
+
/**
|
|
792
|
+
* Patterns for identifying structured data tools
|
|
793
|
+
* Used by: isStructuredDataTool()
|
|
794
|
+
*/
|
|
795
|
+
export const DATA_TOOL_PATTERNS = [
|
|
796
|
+
/search/i,
|
|
797
|
+
/find/i,
|
|
798
|
+
/lookup/i,
|
|
799
|
+
/query/i,
|
|
800
|
+
/retrieve/i,
|
|
801
|
+
/fetch/i,
|
|
802
|
+
/get/i,
|
|
803
|
+
/list/i,
|
|
804
|
+
/resolve/i,
|
|
805
|
+
/discover/i,
|
|
806
|
+
/browse/i,
|
|
807
|
+
];
|
|
808
|
+
/**
|
|
809
|
+
* Read-only tool name patterns
|
|
810
|
+
* Used by: analyzeComputedMathResult()
|
|
811
|
+
*/
|
|
812
|
+
export const READ_ONLY_TOOL_NAME_PATTERN = /^(get|list|fetch|read|retrieve|show|view)_/i;
|
|
813
|
+
// =============================================================================
|
|
814
|
+
// MATH ANALYSIS PATTERNS
|
|
815
|
+
// =============================================================================
|
|
816
|
+
/**
|
|
817
|
+
* Simple math expression pattern
|
|
818
|
+
* Used by: isComputedMathResult(), analyzeComputedMathResult()
|
|
819
|
+
*/
|
|
820
|
+
export const SIMPLE_MATH_PATTERN = /^\s*(\d+)\s*([+\-*/])\s*(\d+)(?:\s*([+\-*/])\s*(\d+))?\s*$/;
|
|
821
|
+
/**
|
|
822
|
+
* Computational language indicators
|
|
823
|
+
* Used by: analyzeComputedMathResult()
|
|
824
|
+
*/
|
|
825
|
+
export const COMPUTATIONAL_INDICATORS = [
|
|
826
|
+
/\bthe\s+answer\s+is\b/i,
|
|
827
|
+
/\bresult\s*[=:]\s*\d/i,
|
|
828
|
+
/\bcalculated\s+to\b/i,
|
|
829
|
+
/\bcomputed\s+as\b/i,
|
|
830
|
+
/\bevaluates?\s+to\b/i,
|
|
831
|
+
/\bequals?\s+\d/i,
|
|
832
|
+
/\bsum\s+is\b/i,
|
|
833
|
+
/\bproduct\s+is\b/i,
|
|
834
|
+
];
|
|
835
|
+
/**
|
|
836
|
+
* Common data field names that often contain numeric values
|
|
837
|
+
* Used by: isCoincidentalNumericInStructuredData()
|
|
838
|
+
*/
|
|
839
|
+
export const STRUCTURED_DATA_FIELD_NAMES = [
|
|
840
|
+
"count",
|
|
841
|
+
"total",
|
|
842
|
+
"records",
|
|
843
|
+
"page",
|
|
844
|
+
"limit",
|
|
845
|
+
"offset",
|
|
846
|
+
"id",
|
|
847
|
+
"status",
|
|
848
|
+
"code",
|
|
849
|
+
"version",
|
|
850
|
+
"index",
|
|
851
|
+
"size",
|
|
852
|
+
"employees",
|
|
853
|
+
"items",
|
|
854
|
+
"results",
|
|
855
|
+
"entries",
|
|
856
|
+
"length",
|
|
857
|
+
"pages",
|
|
858
|
+
"rows",
|
|
859
|
+
"columns",
|
|
860
|
+
"width",
|
|
861
|
+
"height",
|
|
862
|
+
"timestamp",
|
|
863
|
+
"duration",
|
|
864
|
+
"amount",
|
|
865
|
+
"price",
|
|
866
|
+
"quantity",
|
|
867
|
+
];
|
|
868
|
+
// =============================================================================
|
|
869
|
+
// CONFIDENCE CALCULATION PATTERNS
|
|
870
|
+
// =============================================================================
|
|
871
|
+
/**
|
|
872
|
+
* Structured data indicators for confidence calculation
|
|
873
|
+
* Used by: calculateConfidence()
|
|
874
|
+
*/
|
|
875
|
+
export const STRUCTURED_DATA_INDICATORS = {
|
|
876
|
+
fieldPatterns: /title:|name:|description:|trust score:|id:|snippets:/i,
|
|
877
|
+
bulletPattern: /^\s*-\s+/m,
|
|
878
|
+
jsonPattern: /"[^"]+"\s*:\s*"[^"]+"/g,
|
|
879
|
+
numericMetadataPattern: /\b(score|count|trust|rating|id|version)\b/i,
|
|
880
|
+
};
|
|
881
|
+
// =============================================================================
|
|
882
|
+
// HELPER FUNCTIONS
|
|
883
|
+
// =============================================================================
|
|
884
|
+
/**
|
|
885
|
+
* Check if any pattern in array matches text
|
|
886
|
+
*/
|
|
887
|
+
export function matchesAny(patterns, text) {
|
|
888
|
+
return patterns.some((pattern) => pattern.test(text));
|
|
889
|
+
}
|
|
890
|
+
/**
|
|
891
|
+
* Check if HTTP error pattern matches
|
|
892
|
+
*/
|
|
893
|
+
export function isHttpError(text) {
|
|
894
|
+
return (HTTP_ERROR_PATTERNS.statusWithContext.test(text) ||
|
|
895
|
+
HTTP_ERROR_PATTERNS.statusAtStart.test(text) ||
|
|
896
|
+
HTTP_ERROR_PATTERNS.jsonStatus.test(text) ||
|
|
897
|
+
(HTTP_ERROR_PATTERNS.notFound.test(text) && text.length < 100));
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* Check if response has MCP error prefix
|
|
901
|
+
*/
|
|
902
|
+
export function hasMcpErrorPrefix(text) {
|
|
903
|
+
return CONNECTION_ERROR_PATTERNS.mcpPrefix.test(text);
|
|
904
|
+
}
|