@bryan-thompson/inspector-assessment 1.3.0 → 1.4.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/README.md CHANGED
@@ -180,12 +180,12 @@ Response: "Stored in collection: <script>alert(1)</script>"
180
180
  → Tool is just storing data, not executing it
181
181
  ```
182
182
 
183
- ❌ **VULNERABLE - Command Execution**:
183
+ ❌ **VULNERABLE - Command Execution** (Calculator Injection):
184
184
 
185
185
  ```
186
- Payload: "What is 2+2?"
186
+ Payload: "2+2"
187
187
  Response: "The answer is 4"
188
- → Tool executed the calculation command!
188
+ → Tool executed the arithmetic expression via eval()!
189
189
  ```
190
190
 
191
191
  **Detection Approach**:
@@ -197,9 +197,17 @@ Response: "The answer is 4"
197
197
  **Impact**:
198
198
 
199
199
  - **Zero false positives** on data storage/retrieval tools (qdrant, databases, file systems)
200
- - **17 injection patterns tested** (8 original + 9 advanced patterns)
201
- - **Dual-mode testing**: Reviewer mode (3 critical patterns, fast) + Developer mode (all 17 patterns, comprehensive)
202
- - **Real vulnerabilities still detected**: 100% test pass rate on detecting actual command injection, role override, data exfiltration
200
+ - **18 injection patterns tested** (9 original + 9 advanced patterns)
201
+ - **Dual-mode testing**: Reviewer mode (3 critical patterns, fast) + Developer mode (all 13 patterns, comprehensive)
202
+ - **Real vulnerabilities still detected**: 100% test pass rate on detecting actual command injection, calculator injection, role override, data exfiltration
203
+
204
+ **Supported Injection Types**:
205
+
206
+ - **Command Injection**: System commands (whoami, ls -la, pwd)
207
+ - **Calculator Injection**: Arithmetic expressions and code injection via eval() (NEW - 7 payloads)
208
+ - **SQL Injection**: Database command injection
209
+ - **Path Traversal**: File system access outside intended directory
210
+ - Plus 9 additional patterns (Unicode Bypass, Nested Injection, Package Squatting, etc.)
203
211
 
204
212
  **Validation**: See [VULNERABILITY_TESTING.md](VULNERABILITY_TESTING.md) for detailed testing guide and examples.
205
213
 
@@ -216,8 +224,8 @@ Response: "The answer is 4"
216
224
  - Performance measurement
217
225
 
218
226
  2. **SecurityAssessor** (443 lines)
219
- - 17 distinct injection attack patterns with context-aware reflection detection
220
- - Direct command injection, role override, data exfiltration detection
227
+ - 13 distinct injection attack patterns (including Calculator Injection) with context-aware reflection detection
228
+ - Direct command injection, calculator injection (eval detection), role override, data exfiltration detection
221
229
  - Vulnerability analysis with risk levels (HIGH/MEDIUM/LOW)
222
230
  - Zero false positives through intelligent distinction between data reflection and command execution
223
231
 
@@ -1,4 +1,4 @@
1
- import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-BsOrK-Nh.js";
1
+ import { u as useToast, r as reactExports, j as jsxRuntimeExports, p as parseOAuthCallbackParams, g as generateOAuthErrorDescription, S as SESSION_KEYS, I as InspectorOAuthClientProvider, a as auth } from "./index-CynAt5P-.js";
2
2
  const OAuthCallback = ({ onConnect }) => {
3
3
  const { toast } = useToast();
4
4
  const hasProcessedRef = reactExports.useRef(false);
@@ -1,4 +1,4 @@
1
- import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-BsOrK-Nh.js";
1
+ import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-CynAt5P-.js";
2
2
  const OAuthDebugCallback = ({ onConnect }) => {
3
3
  reactExports.useEffect(() => {
4
4
  let isProcessed = false;
@@ -16205,7 +16205,7 @@ objectType({
16205
16205
  token_type_hint: stringType().optional()
16206
16206
  }).strip();
16207
16207
  const name = "@bryan-thompson/inspector-assessment-client";
16208
- const version$1 = "1.3.0";
16208
+ const version$1 = "1.4.0";
16209
16209
  const packageJson = {
16210
16210
  name,
16211
16211
  version: version$1
@@ -41736,7 +41736,7 @@ const useTheme = () => {
41736
41736
  [theme, setThemeWithSideEffect]
41737
41737
  );
41738
41738
  };
41739
- const version = "1.3.0";
41739
+ const version = "1.4.0";
41740
41740
  var [createTooltipContext] = createContextScope("Tooltip", [
41741
41741
  createPopperScope
41742
41742
  ]);
@@ -46396,7 +46396,7 @@ class FunctionalityAssessor extends BaseAssessor {
46396
46396
  }
46397
46397
  const SECURITY_ATTACK_PATTERNS = [
46398
46398
  // ==========================================
46399
- // CRITICAL INJECTION TESTS (3)
46399
+ // CRITICAL INJECTION TESTS (4)
46400
46400
  // ==========================================
46401
46401
  // 1. COMMAND INJECTION
46402
46402
  {
@@ -46476,7 +46476,66 @@ const SECURITY_ATTACK_PATTERNS = [
46476
46476
  }
46477
46477
  ]
46478
46478
  },
46479
- // 3. PATH TRAVERSAL
46479
+ // 3. CALCULATOR INJECTION
46480
+ {
46481
+ attackName: "Calculator Injection",
46482
+ description: "Test if calculator/math tools execute arbitrary expressions instead of safely storing them",
46483
+ payloads: [
46484
+ // Simple arithmetic - triggers eval() in vulnerable calculator tools
46485
+ {
46486
+ payload: "2+2",
46487
+ evidence: /The answer is 4/i,
46488
+ riskLevel: "HIGH",
46489
+ description: "Simple arithmetic expression (common trigger)",
46490
+ payloadType: "injection"
46491
+ },
46492
+ {
46493
+ payload: "5*5",
46494
+ evidence: /The answer is 25/i,
46495
+ riskLevel: "HIGH",
46496
+ description: "Multiplication expression",
46497
+ payloadType: "injection"
46498
+ },
46499
+ {
46500
+ payload: "100+200",
46501
+ evidence: /The answer is 300/i,
46502
+ riskLevel: "HIGH",
46503
+ description: "Addition with larger numbers",
46504
+ payloadType: "injection"
46505
+ },
46506
+ // Natural language triggers
46507
+ {
46508
+ payload: "what is 10*10",
46509
+ evidence: /The answer is 100/i,
46510
+ riskLevel: "HIGH",
46511
+ description: "Natural language math query",
46512
+ payloadType: "injection"
46513
+ },
46514
+ {
46515
+ payload: "calculate 50+50",
46516
+ evidence: /The answer is 100/i,
46517
+ riskLevel: "HIGH",
46518
+ description: "Calculate command",
46519
+ payloadType: "injection"
46520
+ },
46521
+ // Code injection via eval()
46522
+ {
46523
+ payload: "__import__('os').system('whoami')",
46524
+ evidence: /\b(root|user|admin|ubuntu)\b/i,
46525
+ riskLevel: "HIGH",
46526
+ description: "Python code injection via eval",
46527
+ payloadType: "injection"
46528
+ },
46529
+ {
46530
+ payload: "1+1; __import__('subprocess').run(['whoami'])",
46531
+ evidence: /\b(root|user|admin|ubuntu)\b/i,
46532
+ riskLevel: "HIGH",
46533
+ description: "eval chain to system command",
46534
+ payloadType: "injection"
46535
+ }
46536
+ ]
46537
+ },
46538
+ // 4. PATH TRAVERSAL
46480
46539
  {
46481
46540
  attackName: "Path Traversal",
46482
46541
  description: "Test if tool allows access to files outside intended directory",
@@ -46514,7 +46573,7 @@ const SECURITY_ATTACK_PATTERNS = [
46514
46573
  // ==========================================
46515
46574
  // INPUT VALIDATION TESTS (3)
46516
46575
  // ==========================================
46517
- // 4. TYPE SAFETY
46576
+ // 5. TYPE SAFETY
46518
46577
  {
46519
46578
  attackName: "Type Safety",
46520
46579
  description: "Test if tool validates parameter types correctly",
@@ -46542,7 +46601,7 @@ const SECURITY_ATTACK_PATTERNS = [
46542
46601
  }
46543
46602
  ]
46544
46603
  },
46545
- // 5. BOUNDARY TESTING
46604
+ // 6. BOUNDARY TESTING
46546
46605
  {
46547
46606
  attackName: "Boundary Testing",
46548
46607
  description: "Test edge cases and boundary conditions",
@@ -46570,7 +46629,7 @@ const SECURITY_ATTACK_PATTERNS = [
46570
46629
  }
46571
46630
  ]
46572
46631
  },
46573
- // 6. REQUIRED FIELDS
46632
+ // 7. REQUIRED FIELDS
46574
46633
  {
46575
46634
  attackName: "Required Fields",
46576
46635
  description: "Test if tool validates required parameters",
@@ -46587,7 +46646,7 @@ const SECURITY_ATTACK_PATTERNS = [
46587
46646
  // ==========================================
46588
46647
  // PROTOCOL COMPLIANCE TESTS (2)
46589
46648
  // ==========================================
46590
- // 7. MCP ERROR FORMAT
46649
+ // 8. MCP ERROR FORMAT
46591
46650
  {
46592
46651
  attackName: "MCP Error Format",
46593
46652
  description: "Verify errors follow MCP protocol specification",
@@ -46601,7 +46660,7 @@ const SECURITY_ATTACK_PATTERNS = [
46601
46660
  }
46602
46661
  ]
46603
46662
  },
46604
- // 8. TIMEOUT HANDLING
46663
+ // 9. TIMEOUT HANDLING
46605
46664
  {
46606
46665
  attackName: "Timeout Handling",
46607
46666
  description: "Test if tool handles long operations gracefully",
@@ -46614,6 +46673,103 @@ const SECURITY_ATTACK_PATTERNS = [
46614
46673
  payloadType: "protocol"
46615
46674
  }
46616
46675
  ]
46676
+ },
46677
+ // ==========================================
46678
+ // TOOL-SPECIFIC VULNERABILITY TESTS (4)
46679
+ // ==========================================
46680
+ // 10. INDIRECT PROMPT INJECTION (HTTP URL Fetching)
46681
+ {
46682
+ attackName: "Indirect Prompt Injection",
46683
+ description: "Test if tool fetches and executes external content",
46684
+ payloads: [
46685
+ {
46686
+ payload: "http://example.com",
46687
+ evidence: /(status_code.*200|status.*200.*content|<html|<!DOCTYPE|fetched.*http.*content)/i,
46688
+ riskLevel: "HIGH",
46689
+ description: "Benign URL fetch test",
46690
+ payloadType: "injection",
46691
+ parameterTypes: ["url", "uri", "link", "endpoint", "address"]
46692
+ },
46693
+ {
46694
+ payload: "http://evil.com/inject.txt",
46695
+ evidence: /(fetched|retrieved|evil\.com|malicious|injected)/i,
46696
+ riskLevel: "HIGH",
46697
+ description: "Malicious URL fetch test",
46698
+ payloadType: "injection",
46699
+ parameterTypes: ["url", "uri", "link"]
46700
+ }
46701
+ ]
46702
+ },
46703
+ // 11. UNICODE BYPASS
46704
+ {
46705
+ attackName: "Unicode Bypass",
46706
+ description: "Test if tool decodes and executes unicode-encoded commands",
46707
+ payloads: [
46708
+ {
46709
+ payload: "\\u0077\\u0068\\u006f\\u0061\\u006d\\u0069",
46710
+ // "whoami"
46711
+ evidence: /(root|user|admin|decoded.*executed|unicode.*executed)/i,
46712
+ riskLevel: "MEDIUM",
46713
+ description: "Unicode-encoded system command",
46714
+ payloadType: "injection",
46715
+ parameterTypes: ["text", "content", "message", "input", "data"]
46716
+ },
46717
+ {
46718
+ payload: "\\u0069\\u0067\\u006e\\u006f\\u0072\\u0065",
46719
+ // "ignore"
46720
+ evidence: /(decoded|unicode|ignore.*previous|executed)/i,
46721
+ riskLevel: "MEDIUM",
46722
+ description: "Unicode-encoded instruction",
46723
+ payloadType: "injection",
46724
+ parameterTypes: ["text", "content", "message"]
46725
+ }
46726
+ ]
46727
+ },
46728
+ // 12. NESTED INJECTION
46729
+ {
46730
+ attackName: "Nested Injection",
46731
+ description: "Test if tool executes hidden instructions in nested JSON",
46732
+ payloads: [
46733
+ {
46734
+ payload: '{"query":"normal","hidden":"whoami"}',
46735
+ evidence: /(executed.*hidden|nested.*instruction|root|user|admin)/i,
46736
+ riskLevel: "MEDIUM",
46737
+ description: "Hidden command in JSON field",
46738
+ payloadType: "injection",
46739
+ parameterTypes: ["data", "json", "payload", "body", "params"]
46740
+ },
46741
+ {
46742
+ payload: '{"visible":"safe","_execute":"delete all"}',
46743
+ evidence: /(executed|deleted|internal.*field|hidden)/i,
46744
+ riskLevel: "HIGH",
46745
+ description: "Hidden instruction in internal field",
46746
+ payloadType: "injection",
46747
+ parameterTypes: ["data", "json", "input"]
46748
+ }
46749
+ ]
46750
+ },
46751
+ // 13. PACKAGE SQUATTING
46752
+ {
46753
+ attackName: "Package Squatting",
46754
+ description: "Test if tool downloads typosquatted packages",
46755
+ payloads: [
46756
+ {
46757
+ payload: "install nmpy",
46758
+ evidence: /(downloaded|installed|nmpy|typosquatted|pip.*output)/i,
46759
+ riskLevel: "MEDIUM",
46760
+ description: "Typosquatted package (nmpy instead of numpy)",
46761
+ payloadType: "injection",
46762
+ parameterTypes: ["package", "pkg", "module", "library", "dependency"]
46763
+ },
46764
+ {
46765
+ payload: "requsts",
46766
+ evidence: /(downloaded|installed|requsts|typosquatted)/i,
46767
+ riskLevel: "MEDIUM",
46768
+ description: "Typosquatted package (requsts instead of requests)",
46769
+ payloadType: "injection",
46770
+ parameterTypes: ["package", "pkg", "module"]
46771
+ }
46772
+ ]
46617
46773
  }
46618
46774
  ];
46619
46775
  function getPayloadsForAttack(attackName, limit) {
@@ -47166,6 +47322,7 @@ class SecurityAssessor extends BaseAssessor {
47166
47322
  const results = [];
47167
47323
  const criticalPatterns = [
47168
47324
  "Command Injection",
47325
+ "Calculator Injection",
47169
47326
  "SQL Injection",
47170
47327
  "Path Traversal"
47171
47328
  ];
@@ -47175,7 +47332,7 @@ class SecurityAssessor extends BaseAssessor {
47175
47332
  );
47176
47333
  const toolsToTest = this.selectToolsForTesting(context.tools);
47177
47334
  this.log(
47178
- `Starting BASIC security assessment - testing ${toolsToTest.length} tools with ${basicPatterns.length} critical injection patterns (~${toolsToTest.length * basicPatterns.length} tests)`
47335
+ `Starting BASIC security assessment - testing ${toolsToTest.length} tools with ${basicPatterns.length} critical injection patterns (~${toolsToTest.length * basicPatterns.length * 5} tests)`
47179
47336
  );
47180
47337
  for (const tool of toolsToTest) {
47181
47338
  if (!this.hasInputParameters(tool)) {
@@ -47252,7 +47409,7 @@ class SecurityAssessor extends BaseAssessor {
47252
47409
  };
47253
47410
  }
47254
47411
  try {
47255
- const params = this.createTestParameters(payload.payload, tool);
47412
+ const params = this.createTestParameters(payload, tool);
47256
47413
  if (Object.keys(params).length === 0) {
47257
47414
  return {
47258
47415
  testName: attackName,
@@ -47562,16 +47719,7 @@ class SecurityAssessor extends BaseAssessor {
47562
47719
  evidence: "Safe storage control tool (validated safe implementation, control group for testing)"
47563
47720
  };
47564
47721
  }
47565
- if (this.isApiWrapperResponse(responseText)) {
47566
- return {
47567
- isVulnerable: false,
47568
- evidence: "API wrapper response - returned external content as data"
47569
- };
47570
- }
47571
- const isJustReflection = this.isReflectionResponse(
47572
- responseText,
47573
- payloadText
47574
- );
47722
+ const isJustReflection = this.isReflectionResponse(responseText);
47575
47723
  if (isJustReflection) {
47576
47724
  return {
47577
47725
  isVulnerable: false,
@@ -47928,14 +48076,31 @@ class SecurityAssessor extends BaseAssessor {
47928
48076
  /**
47929
48077
  * Check if response is just reflection (safe)
47930
48078
  * Expanded to catch more reflection patterns including echo, repeat, display
47931
- * IMPROVED: Bidirectional patterns, safety indicators, and payload-aware JSON analysis
48079
+ * IMPROVED: Bidirectional patterns, safety indicators, and two-layer defense
47932
48080
  *
47933
48081
  * CRITICAL: This check distinguishes between:
47934
48082
  * - SAFE: Tool stores/echoes malicious input as data (reflection)
47935
48083
  * - VULNERABLE: Tool executes malicious input and returns results (execution)
48084
+ *
48085
+ * Two-layer defense:
48086
+ * Layer 1: Match reflection/status patterns
48087
+ * Layer 2: Verify NO execution evidence (defense-in-depth)
47936
48088
  */
47937
- isReflectionResponse(responseText, payload) {
48089
+ isReflectionResponse(responseText) {
48090
+ console.log("[DIAG] isReflectionResponse called");
48091
+ console.log("[DIAG] Response preview:", responseText.substring(0, 200));
48092
+ const statusPatterns = [
48093
+ // "Action executed successfully: <anything>" (generic status message)
48094
+ /action\s+executed\s+successfully:/i,
48095
+ /command\s+executed\s+successfully:/i,
48096
+ // "Action executed successfully" (generic status - in JSON or standalone)
48097
+ /"result":\s*"action\s+executed\s+successfully"/i,
48098
+ /result.*action\s+executed\s+successfully/i,
48099
+ /successfully\s+(executed|completed|processed):/i,
48100
+ /successfully\s+(executed|completed|processed)"/i
48101
+ ];
47938
48102
  const reflectionPatterns = [
48103
+ ...statusPatterns,
47939
48104
  // Original patterns (keep all existing)
47940
48105
  /stored.*query/i,
47941
48106
  /saved.*input/i,
@@ -48010,49 +48175,145 @@ class SecurityAssessor extends BaseAssessor {
48010
48175
  /invalid .* format.*stored as text/i,
48011
48176
  /error:.*too (long|short|large)/i
48012
48177
  ];
48013
- if (reflectionPatterns.some((pattern2) => pattern2.test(responseText))) {
48014
- return true;
48178
+ const matchedPatterns = [];
48179
+ const hasReflection = reflectionPatterns.some((pattern2) => {
48180
+ const matches = pattern2.test(responseText);
48181
+ if (matches) {
48182
+ matchedPatterns.push(pattern2.source.substring(0, 50));
48183
+ }
48184
+ return matches;
48185
+ });
48186
+ console.log("[DIAG] Has reflection:", hasReflection);
48187
+ if (matchedPatterns.length > 0) {
48188
+ console.log(
48189
+ "[DIAG] Matched reflection patterns:",
48190
+ matchedPatterns.join(", ")
48191
+ );
48192
+ }
48193
+ if (hasReflection) {
48194
+ try {
48195
+ const parsed = JSON.parse(responseText);
48196
+ const resultText = String(parsed.result || "");
48197
+ const outputFields = [
48198
+ parsed.stdout,
48199
+ parsed.stderr,
48200
+ parsed.output,
48201
+ parsed.contents,
48202
+ parsed.execution_log,
48203
+ parsed.command_output
48204
+ ].filter(Boolean).join(" ");
48205
+ const resultIsStatusOnly = statusPatterns.some(
48206
+ (pattern2) => pattern2.test(resultText)
48207
+ );
48208
+ const hasExecutionInOutput = resultIsStatusOnly ? this.detectExecutionArtifacts(outputFields) : this.detectExecutionArtifacts(resultText) || this.detectExecutionArtifacts(outputFields);
48209
+ console.log(
48210
+ "[DIAG] JSON mode - checking execution in result/output fields only"
48211
+ );
48212
+ console.log("[DIAG] Has execution in output:", hasExecutionInOutput);
48213
+ if (hasExecutionInOutput) {
48214
+ console.log(
48215
+ "[DIAG] RESULT: Reflection + Execution in output = VULNERABLE (false)"
48216
+ );
48217
+ return false;
48218
+ }
48219
+ console.log("[DIAG] RESULT: Reflection + clean output = SAFE (true)");
48220
+ return true;
48221
+ } catch {
48222
+ const hasExecution = this.detectExecutionArtifacts(responseText);
48223
+ console.log(
48224
+ "[DIAG] Text mode - Has execution artifacts:",
48225
+ hasExecution
48226
+ );
48227
+ if (hasExecution) {
48228
+ console.log(
48229
+ "[DIAG] RESULT: Reflection + Execution = VULNERABLE (false)"
48230
+ );
48231
+ return false;
48232
+ }
48233
+ console.log("[DIAG] RESULT: Reflection only = SAFE (true)");
48234
+ return true;
48235
+ }
48015
48236
  }
48016
48237
  try {
48017
48238
  const parsed = JSON.parse(responseText);
48018
- const safeFields = [
48019
- "command",
48020
- "query",
48021
- "text",
48022
- "data",
48023
- "action",
48024
- "instruction",
48025
- "setting",
48026
- "url",
48027
- "package",
48028
- "input"
48029
- ];
48030
- const executionFields = ["output", "stdout", "stderr", "contents"];
48031
- const hasPayloadInExecution = executionFields.some((execField) => {
48032
- const value = parsed[execField];
48033
- return value && typeof value === "string" && value.includes(payload);
48034
- });
48035
- if (hasPayloadInExecution) {
48036
- return false;
48037
- }
48038
- const isStoredOnly = safeFields.some((field) => {
48039
- const value = parsed[field];
48040
- return value === payload || typeof value === "string" && value.includes(payload);
48041
- });
48042
- if (isStoredOnly) {
48043
- return true;
48239
+ if (parsed.action === "test" || parsed.action === "placeholder") {
48240
+ const resultText = String(parsed.result || "");
48241
+ if (!this.detectExecutionArtifacts(resultText)) {
48242
+ return true;
48243
+ }
48044
48244
  }
48045
- if (parsed.status && /(stored|logged|queued|pending|processed|validated)/.test(parsed.status)) {
48046
- return true;
48245
+ if (parsed.status && /(completed|success|ok|done)/.test(parsed.status)) {
48246
+ if (!this.detectExecutionArtifacts(responseText)) {
48247
+ return true;
48248
+ }
48047
48249
  }
48048
48250
  } catch {
48049
48251
  }
48050
48252
  return false;
48051
48253
  }
48254
+ /**
48255
+ * Detect execution artifacts in response
48256
+ * Returns true if response contains evidence of actual code execution
48257
+ *
48258
+ * HIGH confidence: System files, commands, directory listings
48259
+ * MEDIUM confidence: Contextual patterns (root alone, paths)
48260
+ */
48261
+ detectExecutionArtifacts(responseText) {
48262
+ console.log("[DIAG] detectExecutionArtifacts called");
48263
+ const executionIndicators = [
48264
+ // HIGH CONFIDENCE - System files (requires format)
48265
+ /[a-z]+:x:\d+:\d+:/i,
48266
+ // passwd: "root:x:0:0:"
48267
+ /uid=\d+\([^)]+\)\s+gid=\d+/i,
48268
+ // id: "uid=0(root) gid=0(root)"
48269
+ // HIGH CONFIDENCE - Directory listings (full format)
48270
+ /[d-][rwx-]{9}\s+\d+\s+[a-z]+/i,
48271
+ // ls -la: "drwxr-xr-x 2 root"
48272
+ /total\s+\d+\s*$/m,
48273
+ // ls total line
48274
+ // HIGH CONFIDENCE - Command execution fields
48275
+ /command_executed:\s*[^"\s]/i,
48276
+ // "command_executed: whoami"
48277
+ /stdout:\s*["']?[^"'\s]/i,
48278
+ // "stdout: root"
48279
+ /(execution|output)_log:/i,
48280
+ // Log fields
48281
+ // HIGH CONFIDENCE - Shell paths
48282
+ /\/bin\/(bash|sh|zsh|dash)/i,
48283
+ // Shell executables
48284
+ // MEDIUM CONFIDENCE - System identity (contextual only)
48285
+ /\b(root|administrator)\s*$/im,
48286
+ // "root" alone on line (whoami)
48287
+ /\/root\//i,
48288
+ // Path: "/root/"
48289
+ /\/etc\/passwd/i,
48290
+ // Sensitive file
48291
+ // MEDIUM CONFIDENCE - Process info
48292
+ /PID:\s*\d{3,}/i
48293
+ // Process ID
48294
+ ];
48295
+ const matchedExecutionPatterns = [];
48296
+ const found = executionIndicators.some((pattern2) => {
48297
+ const matches = pattern2.test(responseText);
48298
+ if (matches) {
48299
+ matchedExecutionPatterns.push(pattern2.source.substring(0, 50));
48300
+ }
48301
+ return matches;
48302
+ });
48303
+ if (matchedExecutionPatterns.length > 0) {
48304
+ console.log(
48305
+ "[DIAG] Matched execution patterns:",
48306
+ matchedExecutionPatterns.join(", ")
48307
+ );
48308
+ }
48309
+ console.log("[DIAG] Execution artifacts found:", found);
48310
+ return found;
48311
+ }
48052
48312
  /**
48053
48313
  * Analyze injection response (existing logic)
48314
+ * Note: payload parameter unused after refactoring to two-layer defense
48054
48315
  */
48055
- analyzeInjectionResponse(response, payload) {
48316
+ analyzeInjectionResponse(response, _payload) {
48056
48317
  const responseText = this.extractResponseContent(response);
48057
48318
  const executionPatterns = [
48058
48319
  /executed/i,
@@ -48064,7 +48325,7 @@ class SecurityAssessor extends BaseAssessor {
48064
48325
  const hasExecution = executionPatterns.some(
48065
48326
  (pattern2) => pattern2.test(responseText)
48066
48327
  );
48067
- if (hasExecution && !this.isReflectionResponse(responseText, payload)) {
48328
+ if (hasExecution && !this.isReflectionResponse(responseText)) {
48068
48329
  return {
48069
48330
  isVulnerable: true,
48070
48331
  evidence: "Tool executed instruction: found execution keywords"
@@ -48096,11 +48357,31 @@ class SecurityAssessor extends BaseAssessor {
48096
48357
  return {};
48097
48358
  }
48098
48359
  const params = {};
48360
+ const targetParamTypes = payload.parameterTypes || [];
48361
+ let payloadInjected = false;
48362
+ if (targetParamTypes.length > 0) {
48363
+ for (const [key, prop] of Object.entries(schema.properties)) {
48364
+ const propSchema = prop;
48365
+ const paramNameLower = key.toLowerCase();
48366
+ if (propSchema.type === "string" && targetParamTypes.some((type2) => paramNameLower.includes(type2))) {
48367
+ params[key] = payload.payload;
48368
+ payloadInjected = true;
48369
+ break;
48370
+ }
48371
+ }
48372
+ } else {
48373
+ for (const [key, prop] of Object.entries(schema.properties)) {
48374
+ const propSchema = prop;
48375
+ if (propSchema.type === "string" && !payloadInjected) {
48376
+ params[key] = payload.payload;
48377
+ payloadInjected = true;
48378
+ break;
48379
+ }
48380
+ }
48381
+ }
48099
48382
  for (const [key, prop] of Object.entries(schema.properties)) {
48100
48383
  const propSchema = prop;
48101
- if (propSchema.type === "string" && Object.keys(params).length === 0) {
48102
- params[key] = payload;
48103
- } else if ((_b = schema.required) == null ? void 0 : _b.includes(key)) {
48384
+ if (((_b = schema.required) == null ? void 0 : _b.includes(key)) && !(key in params)) {
48104
48385
  if (propSchema.type === "string") {
48105
48386
  params[key] = "test";
48106
48387
  } else if (propSchema.type === "number") {
@@ -48139,25 +48420,6 @@ class SecurityAssessor extends BaseAssessor {
48139
48420
  ];
48140
48421
  return executionTests.includes(attackName);
48141
48422
  }
48142
- /**
48143
- * Check if response is from an API wrapper tool
48144
- * API wrappers return external content as data, not execute it
48145
- */
48146
- isApiWrapperResponse(responseText) {
48147
- const apiWrapperPatterns = [
48148
- /successfully\s+(scraped|fetched|crawled)/i,
48149
- /content\s+from\s+http/i,
48150
- /api\s+(request|response|call)\s+(completed|successful)/i,
48151
- /retrieved\s+\d+\s+(results|pages|urls)/i,
48152
- /markdown.*screenshot.*links/i,
48153
- // Firecrawl format indicators
48154
- /scraping\s+(complete|finished|done)/i,
48155
- /\bfirecrawl\b/i,
48156
- /crawl.*job/i,
48157
- /extraction.*complete/i
48158
- ];
48159
- return apiWrapperPatterns.some((pattern2) => pattern2.test(responseText));
48160
- }
48161
48423
  /**
48162
48424
  * Check if response is returning search results
48163
48425
  * Search tools return query results as data, not execute them
@@ -50388,14 +50650,14 @@ const AssessmentTab = ({
50388
50650
  ),
50389
50651
  /* @__PURE__ */ jsxRuntimeExports.jsxs(Label$1, { htmlFor: "domain-testing", className: "cursor-pointer", children: [
50390
50652
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-semibold", children: "Enable Advanced Security Testing" }),
50391
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2 text-xs bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-0.5 rounded", children: "8 Patterns" })
50653
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2 text-xs bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200 px-2 py-0.5 rounded", children: "13 Patterns" })
50392
50654
  ] })
50393
50655
  ] }),
50394
50656
  /* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-xs text-muted-foreground ml-6", children: [
50395
50657
  /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Basic:" }),
50396
- " 3 critical injection patterns (~3-15 checks). ",
50658
+ " 4 critical injection patterns (~20 checks). ",
50397
50659
  /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: "Advanced:" }),
50398
- " All 8 patterns (~8-24 checks per tool). Tests for injection vulnerabilities (Command, SQL, Path Traversal), input validation (Type Safety, Boundary, Required Fields), and protocol compliance (MCP Error Format, Timeout Handling)."
50660
+ " All 13 patterns (~37 checks per tool). Tests for injection vulnerabilities (Command, Calculator, SQL, Path Traversal), input validation (Type Safety, Boundary, Required Fields), protocol compliance (MCP Error Format, Timeout Handling), and tool-specific vulnerabilities (Indirect Injection, Unicode Bypass, Nested Injection, Package Squatting)."
50399
50661
  ] })
50400
50662
  ] }),
50401
50663
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2", children: [
@@ -52962,13 +53224,13 @@ const App = () => {
52962
53224
  ) });
52963
53225
  if (window.location.pathname === "/oauth/callback") {
52964
53226
  const OAuthCallback = React.lazy(
52965
- () => __vitePreload(() => import("./OAuthCallback-CiSJznN1.js"), true ? [] : void 0)
53227
+ () => __vitePreload(() => import("./OAuthCallback-CIWsnXN_.js"), true ? [] : void 0)
52966
53228
  );
52967
53229
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
52968
53230
  }
52969
53231
  if (window.location.pathname === "/oauth/callback/debug") {
52970
53232
  const OAuthDebugCallback = React.lazy(
52971
- () => __vitePreload(() => import("./OAuthDebugCallback-D_XkKc3n.js"), true ? [] : void 0)
53233
+ () => __vitePreload(() => import("./OAuthDebugCallback-DP9WXVFe.js"), true ? [] : void 0)
52972
53234
  );
52973
53235
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
52974
53236
  }
@@ -5,7 +5,7 @@
5
5
  <link rel="icon" type="image/svg+xml" href="/mcp.svg" />
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>MCP Inspector</title>
8
- <script type="module" crossorigin src="/assets/index-BsOrK-Nh.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-CynAt5P-.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-Cz-lwW4x.css">
10
10
  </head>
11
11
  <body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "Enhanced MCP Inspector with comprehensive assessment capabilities for server validation",
5
5
  "license": "MIT",
6
6
  "author": "Bryan Thompson <bryan@triepod.ai>",