@bryan-thompson/inspector-assessment 1.17.0 → 1.17.1

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.
@@ -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-B3FHZqtg.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-sOgf80Op.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-B3FHZqtg.js";
1
+ import { r as reactExports, S as SESSION_KEYS, p as parseOAuthCallbackParams, j as jsxRuntimeExports, g as generateOAuthErrorDescription } from "./index-sOgf80Op.js";
2
2
  const OAuthDebugCallback = ({ onConnect }) => {
3
3
  reactExports.useEffect(() => {
4
4
  let isProcessed = false;
@@ -16320,7 +16320,7 @@ object({
16320
16320
  token_type_hint: string().optional()
16321
16321
  }).strip();
16322
16322
  const name = "@bryan-thompson/inspector-assessment-client";
16323
- const version$1 = "1.16.1";
16323
+ const version$1 = "1.17.1";
16324
16324
  const packageJson = {
16325
16325
  name,
16326
16326
  version: version$1
@@ -45337,7 +45337,7 @@ const useTheme = () => {
45337
45337
  [theme, setThemeWithSideEffect]
45338
45338
  );
45339
45339
  };
45340
- const version = "1.17.0";
45340
+ const version = "1.17.1";
45341
45341
  var [createTooltipContext] = createContextScope("Tooltip", [
45342
45342
  createPopperScope
45343
45343
  ]);
@@ -58267,13 +58267,13 @@ const App = () => {
58267
58267
  ) });
58268
58268
  if (window.location.pathname === "/oauth/callback") {
58269
58269
  const OAuthCallback = React.lazy(
58270
- () => __vitePreload(() => import("./OAuthCallback-DKHgeaa0.js"), true ? [] : void 0)
58270
+ () => __vitePreload(() => import("./OAuthCallback-DRaMXbvu.js"), true ? [] : void 0)
58271
58271
  );
58272
58272
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthCallback, { onConnect: onOAuthConnect }) });
58273
58273
  }
58274
58274
  if (window.location.pathname === "/oauth/callback/debug") {
58275
58275
  const OAuthDebugCallback = React.lazy(
58276
- () => __vitePreload(() => import("./OAuthDebugCallback-5vclGNC-.js"), true ? [] : void 0)
58276
+ () => __vitePreload(() => import("./OAuthDebugCallback-Dj_-SG3N.js"), true ? [] : void 0)
58277
58277
  );
58278
58278
  return /* @__PURE__ */ jsxRuntimeExports.jsx(reactExports.Suspense, { fallback: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntimeExports.jsx(OAuthDebugCallback, { onConnect: onOAuthDebugConnect }) });
58279
58279
  }
@@ -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-B3FHZqtg.js"></script>
8
+ <script type="module" crossorigin src="/assets/index-sOgf80Op.js"></script>
9
9
  <link rel="stylesheet" crossorigin href="/assets/index-CzoGuYPy.css">
10
10
  </head>
11
11
  <body>
@@ -18,6 +18,11 @@ export declare class TemporalAssessor extends BaseAssessor {
18
18
  * These tools legitimately return different results based on data state,
19
19
  * which is NOT a rug pull vulnerability (e.g., search returning more results
20
20
  * after other tools have stored data).
21
+ *
22
+ * NOTE: Uses substring matching, so "get" matches "get_user", "forget",
23
+ * "target", etc. This favors recall over precision - we prefer lenient
24
+ * schema comparison for edge cases over false positives on legitimate tools.
25
+ * Consider word-boundary regex if false positives become problematic.
21
26
  */
22
27
  private readonly STATEFUL_TOOL_PATTERNS;
23
28
  constructor(config: AssessmentConfiguration);
@@ -55,7 +60,7 @@ export declare class TemporalAssessor extends BaseAssessor {
55
60
  private compareSchemas;
56
61
  /**
57
62
  * Extract all field names from an object recursively.
58
- * Handles arrays by sampling the first element's schema with [] notation.
63
+ * Handles arrays by sampling multiple elements to detect heterogeneous schemas.
59
64
  */
60
65
  private extractFieldNames;
61
66
  private determineTemporalStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"TemporalAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/TemporalAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,uBAAuB,EAEvB,kBAAkB,EAEnB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAY9C,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,kBAAkB,CAAS;IAGnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAoBnC;IAGF,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAU;IAEjD;;;;;OAKG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CASrC;gBAEU,MAAM,EAAE,uBAAuB;IAKrC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;YA8CvD,UAAU;IAkExB,OAAO,CAAC,gBAAgB;IAgFxB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsC3B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAoDzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAOtB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAiBtB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,uBAAuB;CA8BhC"}
1
+ {"version":3,"file":"TemporalAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/TemporalAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,uBAAuB,EAEvB,kBAAkB,EAEnB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAY9C,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,kBAAkB,CAAS;IAGnC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAoBnC;IAGF,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAAU;IAEjD;;;;;;;;;;OAUG;IACH,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CASrC;gBAEU,MAAM,EAAE,uBAAuB;IAKrC,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;YA8CvD,UAAU;IAkExB,OAAO,CAAC,gBAAgB;IAmFxB;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAsC3B;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAoDzB;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAKzB;;;;OAIG;IACH,OAAO,CAAC,cAAc;IAYtB;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAuBtB;;;OAGG;IACH,OAAO,CAAC,iBAAiB;IAiCzB,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,mBAAmB;IAoB3B,OAAO,CAAC,uBAAuB;CA8BhC"}
@@ -40,6 +40,11 @@ export class TemporalAssessor extends BaseAssessor {
40
40
  * These tools legitimately return different results based on data state,
41
41
  * which is NOT a rug pull vulnerability (e.g., search returning more results
42
42
  * after other tools have stored data).
43
+ *
44
+ * NOTE: Uses substring matching, so "get" matches "get_user", "forget",
45
+ * "target", etc. This favors recall over precision - we prefer lenient
46
+ * schema comparison for edge cases over false positives on legitimate tools.
47
+ * Consider word-boundary regex if false positives become problematic.
43
48
  */
44
49
  STATEFUL_TOOL_PATTERNS = [
45
50
  "search",
@@ -157,6 +162,9 @@ export class TemporalAssessor extends BaseAssessor {
157
162
  // For stateful tools (search, list, etc.), use schema comparison instead of exact match
158
163
  // These tools legitimately return different content based on data state
159
164
  const isStateful = this.isStatefulTool(tool);
165
+ if (isStateful) {
166
+ this.log(`${tool.name} classified as stateful - using schema comparison`);
167
+ }
160
168
  for (let i = 1; i < responses.length; i++) {
161
169
  if (responses[i].error) {
162
170
  errors.push(i + 1); // Track errors as potential indicators
@@ -298,6 +306,11 @@ export class TemporalAssessor extends BaseAssessor {
298
306
  */
299
307
  isStatefulTool(tool) {
300
308
  const toolName = tool.name.toLowerCase();
309
+ // Exclude tools that are ALSO destructive - they should get strict exact comparison
310
+ // e.g., "get_and_delete" matches both "get" (stateful) and "delete" (destructive)
311
+ if (this.isDestructiveTool(tool)) {
312
+ return false;
313
+ }
301
314
  return this.STATEFUL_TOOL_PATTERNS.some((pattern) => toolName.includes(pattern));
302
315
  }
303
316
  /**
@@ -310,6 +323,11 @@ export class TemporalAssessor extends BaseAssessor {
310
323
  compareSchemas(response1, response2) {
311
324
  const fields1 = this.extractFieldNames(response1).sort();
312
325
  const fields2 = this.extractFieldNames(response2).sort();
326
+ // Edge case: empty baseline with populated later response is suspicious
327
+ // An attacker could start with {} then switch to content with malicious fields
328
+ if (fields1.length === 0 && fields2.length > 0) {
329
+ return false; // Flag as schema mismatch
330
+ }
313
331
  // Check for exact match (handles non-array cases)
314
332
  const exactMatch = fields1.join(",") === fields2.join(",");
315
333
  if (exactMatch)
@@ -323,18 +341,24 @@ export class TemporalAssessor extends BaseAssessor {
323
341
  }
324
342
  /**
325
343
  * Extract all field names from an object recursively.
326
- * Handles arrays by sampling the first element's schema with [] notation.
344
+ * Handles arrays by sampling multiple elements to detect heterogeneous schemas.
327
345
  */
328
346
  extractFieldNames(obj, prefix = "") {
329
347
  if (obj === null || obj === undefined || typeof obj !== "object")
330
348
  return [];
331
349
  const fields = [];
332
- // Handle arrays: sample first element's schema
350
+ // Handle arrays: sample multiple elements to detect heterogeneous schemas
351
+ // An attacker could hide malicious fields in non-first array elements
333
352
  if (Array.isArray(obj)) {
334
- if (obj.length > 0 && typeof obj[0] === "object" && obj[0] !== null) {
335
- const arrayItemFields = this.extractFieldNames(obj[0], `${prefix}[]`);
336
- fields.push(...arrayItemFields);
353
+ const samplesToCheck = Math.min(obj.length, 3); // Check up to 3 elements
354
+ const seenFields = new Set();
355
+ for (let i = 0; i < samplesToCheck; i++) {
356
+ if (typeof obj[i] === "object" && obj[i] !== null) {
357
+ const itemFields = this.extractFieldNames(obj[i], `${prefix}[]`);
358
+ itemFields.forEach((f) => seenFields.add(f));
359
+ }
337
360
  }
361
+ fields.push(...seenFields);
338
362
  return fields;
339
363
  }
340
364
  // Handle objects
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bryan-thompson/inspector-assessment",
3
- "version": "1.17.0",
3
+ "version": "1.17.1",
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>",