@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.
Files changed (80) hide show
  1. package/cli/build/lib/assessment-runner/assessment-executor.js +29 -1
  2. package/cli/build/lib/assessment-runner/source-loader.js +11 -0
  3. package/cli/package.json +1 -1
  4. package/client/dist/assets/{OAuthCallback-6-wM7Zc1.js → OAuthCallback-AngeBaCl.js} +1 -1
  5. package/client/dist/assets/{OAuthDebugCallback-Bw9-AzzP.js → OAuthDebugCallback--FE6_fPs.js} +1 -1
  6. package/client/dist/assets/{index-DyCdQP10.js → index-BQC95Boo.js} +4 -4
  7. package/client/dist/index.html +1 -1
  8. package/client/lib/lib/assessment/coreTypes.d.ts +37 -0
  9. package/client/lib/lib/assessment/coreTypes.d.ts.map +1 -1
  10. package/client/lib/lib/assessment/resultTypes.d.ts +26 -1
  11. package/client/lib/lib/assessment/resultTypes.d.ts.map +1 -1
  12. package/client/lib/lib/securityPatterns/advancedExploitPatterns.d.ts +13 -0
  13. package/client/lib/lib/securityPatterns/advancedExploitPatterns.d.ts.map +1 -0
  14. package/client/lib/lib/securityPatterns/advancedExploitPatterns.js +504 -0
  15. package/client/lib/lib/securityPatterns/authSessionPatterns.d.ts +12 -0
  16. package/client/lib/lib/securityPatterns/authSessionPatterns.d.ts.map +1 -0
  17. package/client/lib/lib/securityPatterns/authSessionPatterns.js +357 -0
  18. package/client/lib/lib/securityPatterns/index.d.ts +18 -0
  19. package/client/lib/lib/securityPatterns/index.d.ts.map +1 -0
  20. package/client/lib/lib/securityPatterns/index.js +18 -0
  21. package/client/lib/lib/securityPatterns/injectionPatterns.d.ts +13 -0
  22. package/client/lib/lib/securityPatterns/injectionPatterns.d.ts.map +1 -0
  23. package/client/lib/lib/securityPatterns/injectionPatterns.js +356 -0
  24. package/client/lib/lib/securityPatterns/resourceExhaustionPatterns.d.ts +12 -0
  25. package/client/lib/lib/securityPatterns/resourceExhaustionPatterns.d.ts.map +1 -0
  26. package/client/lib/lib/securityPatterns/resourceExhaustionPatterns.js +215 -0
  27. package/client/lib/lib/securityPatterns/toolSpecificPatterns.d.ts +13 -0
  28. package/client/lib/lib/securityPatterns/toolSpecificPatterns.d.ts.map +1 -0
  29. package/client/lib/lib/securityPatterns/toolSpecificPatterns.js +373 -0
  30. package/client/lib/lib/securityPatterns/types.d.ts +20 -0
  31. package/client/lib/lib/securityPatterns/types.d.ts.map +1 -0
  32. package/client/lib/lib/securityPatterns/types.js +6 -0
  33. package/client/lib/lib/securityPatterns/utils.d.ts +56 -0
  34. package/client/lib/lib/securityPatterns/utils.d.ts.map +1 -0
  35. package/client/lib/lib/securityPatterns/utils.js +96 -0
  36. package/client/lib/lib/securityPatterns/validationPatterns.d.ts +13 -0
  37. package/client/lib/lib/securityPatterns/validationPatterns.d.ts.map +1 -0
  38. package/client/lib/lib/securityPatterns/validationPatterns.js +110 -0
  39. package/client/lib/lib/securityPatterns.d.ts +18 -69
  40. package/client/lib/lib/securityPatterns.d.ts.map +1 -1
  41. package/client/lib/lib/securityPatterns.js +18 -1946
  42. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts +4 -1
  43. package/client/lib/services/assessment/AssessmentOrchestrator.d.ts.map +1 -1
  44. package/client/lib/services/assessment/helpers/ExternalAPIDependencyDetector.d.ts +96 -5
  45. package/client/lib/services/assessment/helpers/ExternalAPIDependencyDetector.d.ts.map +1 -1
  46. package/client/lib/services/assessment/helpers/ExternalAPIDependencyDetector.js +202 -16
  47. package/client/lib/services/assessment/helpers/StdioTransportDetector.d.ts +137 -0
  48. package/client/lib/services/assessment/helpers/StdioTransportDetector.d.ts.map +1 -0
  49. package/client/lib/services/assessment/helpers/StdioTransportDetector.js +315 -0
  50. package/client/lib/services/assessment/helpers/ToolAnnotationExtractor.d.ts +34 -0
  51. package/client/lib/services/assessment/helpers/ToolAnnotationExtractor.d.ts.map +1 -0
  52. package/client/lib/services/assessment/helpers/ToolAnnotationExtractor.js +85 -0
  53. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts +17 -0
  54. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.d.ts.map +1 -1
  55. package/client/lib/services/assessment/modules/ErrorHandlingAssessor.js +162 -10
  56. package/client/lib/services/assessment/modules/ProtocolComplianceAssessor.d.ts.map +1 -1
  57. package/client/lib/services/assessment/modules/ProtocolComplianceAssessor.js +30 -0
  58. package/client/lib/services/assessment/modules/SecurityAssessor.d.ts.map +1 -1
  59. package/client/lib/services/assessment/modules/SecurityAssessor.js +6 -0
  60. package/client/lib/services/assessment/modules/securityTests/AnnotationAwareSeverity.d.ts +55 -0
  61. package/client/lib/services/assessment/modules/securityTests/AnnotationAwareSeverity.d.ts.map +1 -0
  62. package/client/lib/services/assessment/modules/securityTests/AnnotationAwareSeverity.js +135 -0
  63. package/client/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts +6 -0
  64. package/client/lib/services/assessment/modules/securityTests/SafeResponseDetector.d.ts.map +1 -1
  65. package/client/lib/services/assessment/modules/securityTests/SafeResponseDetector.js +9 -1
  66. package/client/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts +20 -0
  67. package/client/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.d.ts.map +1 -1
  68. package/client/lib/services/assessment/modules/securityTests/SecurityPatternLibrary.js +37 -0
  69. package/client/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts +11 -1
  70. package/client/lib/services/assessment/modules/securityTests/SecurityPayloadTester.d.ts.map +1 -1
  71. package/client/lib/services/assessment/modules/securityTests/SecurityPayloadTester.js +26 -1
  72. package/client/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts +1 -1
  73. package/client/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.d.ts.map +1 -1
  74. package/client/lib/services/assessment/modules/securityTests/SecurityResponseAnalyzer.js +10 -1
  75. package/client/lib/services/assessment/modules/securityTests/index.d.ts +1 -0
  76. package/client/lib/services/assessment/modules/securityTests/index.d.ts.map +1 -1
  77. package/client/lib/services/assessment/modules/securityTests/index.js +1 -0
  78. package/client/package.json +1 -1
  79. package/package.json +1 -1
  80. package/server/package.json +1 -1
@@ -365,11 +365,15 @@ export class ErrorHandlingAssessor extends BaseAssessor {
365
365
  }
366
366
  async testInvalidValues(tool, callTool, isExternalAPI = false) {
367
367
  const schema = this.getToolSchema(tool);
368
- const testInput = this.generateInvalidValueParams(schema);
368
+ // Issue #173: Destructure metadata from new return type
369
+ const { params: testInput, testedParameter, parameterIsRequired, } = this.generateInvalidValueParams(schema);
369
370
  try {
370
371
  const response = await this.executeWithTimeout(callTool(tool.name, testInput), 5000);
371
372
  const isError = this.isErrorResponse(response);
372
373
  const errorInfo = this.extractErrorInfo(response);
374
+ const responseText = this.extractResponseTextSafe(response);
375
+ // Issue #173: Detect suggestions in response
376
+ const { hasSuggestions, suggestions } = this.detectSuggestionPatterns(responseText);
373
377
  // Issue #168: For external API tools, check if error is an external service error
374
378
  if (isExternalAPI && isError && this.isExternalServiceError(errorInfo)) {
375
379
  return {
@@ -385,6 +389,11 @@ export class ErrorHandlingAssessor extends BaseAssessor {
385
389
  },
386
390
  passed: true,
387
391
  reason: "External API service error (validation cannot be tested when service unavailable)",
392
+ // Issue #173 metadata
393
+ testedParameter,
394
+ parameterIsRequired,
395
+ hasSuggestions,
396
+ suggestions: suggestions.length > 0 ? suggestions : undefined,
388
397
  };
389
398
  }
390
399
  // For invalid values, any error response is good
@@ -402,6 +411,11 @@ export class ErrorHandlingAssessor extends BaseAssessor {
402
411
  },
403
412
  passed: isError,
404
413
  reason: isError ? undefined : "Tool accepted invalid values",
414
+ // Issue #173 metadata
415
+ testedParameter,
416
+ parameterIsRequired,
417
+ hasSuggestions,
418
+ suggestions: suggestions.length > 0 ? suggestions : undefined,
405
419
  };
406
420
  }
407
421
  catch (error) {
@@ -422,6 +436,9 @@ export class ErrorHandlingAssessor extends BaseAssessor {
422
436
  passed: false,
423
437
  reason: "Connection error - unable to test",
424
438
  isConnectionError: true,
439
+ // Issue #173 metadata
440
+ testedParameter,
441
+ parameterIsRequired,
425
442
  };
426
443
  }
427
444
  // Check if the error message is meaningful (not just a generic crash)
@@ -434,6 +451,8 @@ export class ErrorHandlingAssessor extends BaseAssessor {
434
451
  messageLower.includes("validation") ||
435
452
  messageLower.includes("error");
436
453
  // Removed: (errorInfo.message?.length ?? 0) > 15 - this was causing false positives
454
+ // Issue #173: Detect suggestions in error message
455
+ const { hasSuggestions, suggestions } = this.detectSuggestionPatterns(messageLower);
437
456
  return {
438
457
  toolName: tool.name,
439
458
  testType: "invalid_values",
@@ -447,6 +466,11 @@ export class ErrorHandlingAssessor extends BaseAssessor {
447
466
  },
448
467
  passed: isMeaningfulError,
449
468
  reason: isMeaningfulError ? undefined : "Generic unhandled exception",
469
+ // Issue #173 metadata
470
+ testedParameter,
471
+ parameterIsRequired,
472
+ hasSuggestions,
473
+ suggestions: suggestions.length > 0 ? suggestions : undefined,
450
474
  };
451
475
  }
452
476
  }
@@ -569,11 +593,26 @@ export class ErrorHandlingAssessor extends BaseAssessor {
569
593
  }
570
594
  return params;
571
595
  }
596
+ /**
597
+ * Issue #173: Return type for generateInvalidValueParams with metadata
598
+ * Tracks which parameter is being tested and whether it's required
599
+ */
572
600
  generateInvalidValueParams(schema) {
573
601
  const params = {};
574
- if (!schema?.properties)
575
- return { value: null };
602
+ let testedParameter = "value";
603
+ let parameterIsRequired = false;
604
+ if (!schema?.properties) {
605
+ return { params: { value: null }, testedParameter, parameterIsRequired };
606
+ }
607
+ const requiredSet = new Set(schema.required ?? []);
608
+ let firstParamSet = false;
576
609
  for (const [key, prop] of Object.entries(schema.properties)) {
610
+ // Track the first parameter being tested (for contextual scoring)
611
+ if (!firstParamSet) {
612
+ testedParameter = key;
613
+ parameterIsRequired = requiredSet.has(key);
614
+ firstParamSet = true;
615
+ }
577
616
  if (prop.type === "string") {
578
617
  if (prop.enum) {
579
618
  params[key] = "not_in_enum"; // Value not in enum
@@ -600,7 +639,7 @@ export class ErrorHandlingAssessor extends BaseAssessor {
600
639
  }
601
640
  }
602
641
  }
603
- return params;
642
+ return { params, testedParameter, parameterIsRequired };
604
643
  }
605
644
  generateParamsWithValue(tool, value) {
606
645
  const schema = this.getToolSchema(tool);
@@ -623,11 +662,13 @@ export class ErrorHandlingAssessor extends BaseAssessor {
623
662
  /**
624
663
  * Analyze invalid_values response to determine scoring impact
625
664
  * Issue #99: Contextual empty string validation scoring
665
+ * Issue #173: Bonus points for suggestions and graceful degradation
626
666
  *
627
667
  * Classifications:
628
668
  * - safe_rejection: Tool rejected with error (no penalty)
629
669
  * - safe_reflection: Tool stored/echoed without executing (no penalty)
630
670
  * - defensive_programming: Tool handled gracefully (no penalty)
671
+ * - graceful_degradation: Optional param handled with neutral response (no penalty + bonus)
631
672
  * - execution_detected: Tool executed input (penalty)
632
673
  * - unknown: Cannot determine (partial penalty)
633
674
  */
@@ -635,14 +676,30 @@ export class ErrorHandlingAssessor extends BaseAssessor {
635
676
  const responseText = this.extractResponseTextSafe(test.actualResponse.rawResponse);
636
677
  // Case 1: Tool rejected with error - best case (no penalty)
637
678
  if (test.actualResponse.isError) {
679
+ // Issue #173: Check for suggestions bonus
680
+ const suggestionBonus = test.hasSuggestions ? 10 : 0;
638
681
  return {
639
682
  shouldPenalize: false,
640
683
  penaltyAmount: 0,
641
684
  classification: "safe_rejection",
642
685
  reason: "Tool properly rejected invalid input",
686
+ bonusPoints: suggestionBonus,
687
+ };
688
+ }
689
+ // Issue #173 Case 2: Graceful degradation for OPTIONAL parameters
690
+ // If the parameter is optional and the response is neutral (empty results),
691
+ // this is valid graceful degradation behavior, not a failure
692
+ if (test.parameterIsRequired === false &&
693
+ this.isNeutralGracefulResponse(responseText)) {
694
+ return {
695
+ shouldPenalize: false,
696
+ penaltyAmount: 0,
697
+ classification: "graceful_degradation",
698
+ reason: "Tool handled optional empty parameter gracefully (valid behavior)",
699
+ bonusPoints: 15, // Graceful degradation bonus
643
700
  };
644
701
  }
645
- // Case 2: Defensive programming patterns (no penalty)
702
+ // Case 3: Defensive programming patterns (no penalty)
646
703
  // Check BEFORE execution detection because patterns like "query returned 0"
647
704
  // might match execution indicators but are actually safe
648
705
  if (this.isDefensiveProgrammingResponse(responseText)) {
@@ -651,18 +708,20 @@ export class ErrorHandlingAssessor extends BaseAssessor {
651
708
  penaltyAmount: 0,
652
709
  classification: "defensive_programming",
653
710
  reason: "Tool handled empty input defensively",
711
+ bonusPoints: 0,
654
712
  };
655
713
  }
656
- // Case 3: Safe reflection patterns (no penalty)
714
+ // Case 4: Safe reflection patterns (no penalty)
657
715
  if (this.safeResponseDetector.isReflectionResponse(responseText)) {
658
716
  return {
659
717
  shouldPenalize: false,
660
718
  penaltyAmount: 0,
661
719
  classification: "safe_reflection",
662
720
  reason: "Tool safely reflected input without execution",
721
+ bonusPoints: 0,
663
722
  };
664
723
  }
665
- // Case 4: Check for execution evidence - VULNERABLE (full penalty)
724
+ // Case 5: Check for execution evidence - VULNERABLE (full penalty)
666
725
  if (this.executionDetector.hasExecutionEvidence(responseText) ||
667
726
  this.executionDetector.detectExecutionArtifacts(responseText)) {
668
727
  return {
@@ -670,14 +729,16 @@ export class ErrorHandlingAssessor extends BaseAssessor {
670
729
  penaltyAmount: 100,
671
730
  classification: "execution_detected",
672
731
  reason: "Tool executed input without validation",
732
+ bonusPoints: 0,
673
733
  };
674
734
  }
675
- // Case 5: Unknown - partial penalty for manual review
735
+ // Case 6: Unknown - partial penalty for manual review
676
736
  return {
677
737
  shouldPenalize: true,
678
738
  penaltyAmount: 25,
679
739
  classification: "unknown",
680
740
  reason: "Unable to determine safety - manual review recommended",
741
+ bonusPoints: 0,
681
742
  };
682
743
  }
683
744
  /**
@@ -715,10 +776,76 @@ export class ErrorHandlingAssessor extends BaseAssessor {
715
776
  ];
716
777
  return patterns.some((p) => p.test(responseText));
717
778
  }
779
+ /**
780
+ * Issue #173: Detect helpful suggestion patterns in error responses
781
+ * Patterns like: "Did you mean: Button, Checkbox?"
782
+ * Returns extracted suggestions for bonus scoring
783
+ */
784
+ detectSuggestionPatterns(responseText) {
785
+ // Issue #173: ReDoS protection - limit input length before regex matching
786
+ const truncatedText = responseText.slice(0, 2000);
787
+ // Issue #173: Bonus points - see docs/ASSESSMENT_CATALOG.md for scoring table
788
+ // Suggestions: +10 points for helpful error messages like "Did you mean: X?"
789
+ const suggestionPatterns = [
790
+ /did\s+you\s+mean[:\s]+([^?.]+)/i,
791
+ /perhaps\s+you\s+meant[:\s]+([^?.]+)/i,
792
+ /similar\s+to[:\s]+([^?.]+)/i,
793
+ /suggestions?[:\s]+([^?.]+)/i,
794
+ /valid\s+(options?|values?)[:\s]+([^?.]+)/i,
795
+ /available[:\s]+([^?.]+)/i,
796
+ /\btry[:\s]+([^?.]+)/i,
797
+ /expected\s+one\s+of[:\s]+([^?.]+)/i,
798
+ ];
799
+ for (const pattern of suggestionPatterns) {
800
+ const match = truncatedText.match(pattern);
801
+ if (match) {
802
+ // Get the captured group (last non-undefined group)
803
+ const suggestionText = match[match.length - 1] || match[1] || "";
804
+ const suggestions = suggestionText
805
+ .split(/[,;]/)
806
+ .map((s) => s.trim())
807
+ .filter((s) => s.length > 0 && s.length < 50);
808
+ if (suggestions.length > 0) {
809
+ return { hasSuggestions: true, suggestions };
810
+ }
811
+ }
812
+ }
813
+ return { hasSuggestions: false, suggestions: [] };
814
+ }
815
+ /**
816
+ * Issue #173: Check for neutral/graceful responses on optional parameters
817
+ * These indicate the tool handled empty/missing optional input appropriately
818
+ */
819
+ isNeutralGracefulResponse(responseText) {
820
+ // Issue #173: ReDoS protection - limit input length before regex matching
821
+ const truncatedText = responseText.slice(0, 2000);
822
+ const gracefulPatterns = [
823
+ /^\s*\[\s*\]\s*$/, // Empty JSON array (standalone)
824
+ /^\s*\{\s*\}\s*$/, // Empty JSON object (standalone)
825
+ /^\s*$/, // Empty/whitespace only response
826
+ /no\s+results?\s*(found)?/i, // "No results" / "No results found"
827
+ /^results?:\s*\[\s*\]/i, // "results: []"
828
+ /returned\s+0\s+/i, // "returned 0 items"
829
+ /found\s+0\s+/i, // "found 0 matches"
830
+ /empty\s+list/i, // "empty list"
831
+ /no\s+matching/i, // "no matching items"
832
+ /default\s+value/i, // "using default value"
833
+ /^null$/i, // Explicit null
834
+ /no\s+data/i, // "no data"
835
+ /"results"\s*:\s*\[\s*\]/, // JSON with empty results array
836
+ /"items"\s*:\s*\[\s*\]/, // JSON with empty items array
837
+ /"data"\s*:\s*\[\s*\]/, // JSON with empty data array
838
+ ];
839
+ return gracefulPatterns.some((pattern) => pattern.test(truncatedText));
840
+ }
718
841
  calculateMetrics(tests, _passed) {
719
842
  // Calculate enhanced score with bonus points for quality
720
843
  let enhancedScore = 0;
721
844
  let maxPossibleScore = 0;
845
+ // Issue #173: Track graceful degradation and suggestion metrics
846
+ let gracefulDegradationCount = 0;
847
+ let suggestionCount = 0;
848
+ let suggestionBonusPoints = 0;
722
849
  tests.forEach((test) => {
723
850
  // Issue #99: Contextual scoring for invalid_values tests
724
851
  // Instead of blanket exclusion, analyze response patterns to determine if
@@ -726,9 +853,23 @@ export class ErrorHandlingAssessor extends BaseAssessor {
726
853
  // or if it executed without validation (security concern).
727
854
  if (test.testType === "invalid_values") {
728
855
  const analysis = this.analyzeInvalidValuesResponse(test);
856
+ // Issue #173: Track graceful degradation
857
+ if (analysis.classification === "graceful_degradation") {
858
+ gracefulDegradationCount++;
859
+ }
860
+ // Issue #173: Track suggestions
861
+ if (test.hasSuggestions) {
862
+ suggestionCount++;
863
+ }
864
+ // Issue #173: Apply bonus points for graceful handling and suggestions
865
+ if (analysis.bonusPoints > 0) {
866
+ enhancedScore += analysis.bonusPoints;
867
+ maxPossibleScore += analysis.bonusPoints;
868
+ suggestionBonusPoints += analysis.bonusPoints;
869
+ }
729
870
  if (!analysis.shouldPenalize) {
730
- // Safe response (rejection, reflection, or defensive programming)
731
- // Skip scoring to preserve backward compatibility for well-behaved tools
871
+ // Safe response (rejection, reflection, defensive programming, graceful degradation)
872
+ // Skip base scoring to preserve backward compatibility for well-behaved tools
732
873
  return;
733
874
  }
734
875
  // Execution detected or unknown - include in scoring with penalty
@@ -756,6 +897,13 @@ export class ErrorHandlingAssessor extends BaseAssessor {
756
897
  enhancedScore += 5;
757
898
  maxPossibleScore += 5;
758
899
  }
900
+ // Issue #173: Extra points for suggestions in other test types
901
+ if (test.hasSuggestions) {
902
+ suggestionCount++;
903
+ enhancedScore += 10;
904
+ maxPossibleScore += 10;
905
+ suggestionBonusPoints += 10;
906
+ }
759
907
  }
760
908
  });
761
909
  const score = maxPossibleScore > 0 ? (enhancedScore / maxPossibleScore) * 100 : 0;
@@ -796,6 +944,10 @@ export class ErrorHandlingAssessor extends BaseAssessor {
796
944
  hasDescriptiveMessages,
797
945
  validatesInputs,
798
946
  testDetails: tests,
947
+ // Issue #173: Graceful degradation and suggestion metrics
948
+ gracefulDegradationCount,
949
+ suggestionCount,
950
+ suggestionBonusPoints,
799
951
  };
800
952
  }
801
953
  determineErrorHandlingStatus(metrics, testCount) {
@@ -1 +1 @@
1
- {"version":3,"file":"ProtocolComplianceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ProtocolComplianceAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,2BAA2B,EAM3B,uBAAuB,EAMxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAOpE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAmB9D;;;GAGG;AACH,MAAM,WAAW,4BAA6B,SAAQ,2BAA2B;IAC/E,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE;QAClB,mBAAmB,EAAE,aAAa,CAAC;QACnC,kBAAkB,EAAE,aAAa,CAAC;QAClC,uBAAuB,EAAE,aAAa,CAAC;KACxC,CAAC;CACH;AAED,qBAAa,0BAA2B,SAAQ,YAAY,CAAC,4BAA4B,CAAC;IACxF,OAAO,CAAC,GAAG,CAAc;gBAEb,MAAM,EAAE,uBAAuB;IAK3C;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,4BAA4B,CAAC;IAyIxC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;YACW,sBAAsB;IAuBpC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwC7B;;OAEG;YACW,mBAAmB;IAiCjC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAiDnC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAkEnC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAS7B;;OAEG;YACW,wBAAwB;IA4GtC;;OAEG;YACW,uBAAuB;IA2FrC;;OAEG;YACW,4BAA4B;IAoD1C,OAAO,CAAC,yBAAyB;IAkEjC,OAAO,CAAC,uBAAuB;IAqB/B,OAAO,CAAC,sBAAsB;IA0B9B,OAAO,CAAC,qBAAqB;IAgC7B,OAAO,CAAC,oBAAoB;IA8E5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAqEhC"}
1
+ {"version":3,"file":"ProtocolComplianceAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/ProtocolComplianceAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EACL,2BAA2B,EAM3B,uBAAuB,EAMxB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gCAAgC,CAAC;AAOpE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAmB9D;;;GAGG;AACH,MAAM,WAAW,4BAA6B,SAAQ,2BAA2B;IAC/E,2EAA2E;IAC3E,iBAAiB,CAAC,EAAE;QAClB,mBAAmB,EAAE,aAAa,CAAC;QACnC,kBAAkB,EAAE,aAAa,CAAC;QAClC,uBAAuB,EAAE,aAAa,CAAC;KACxC,CAAC;CACH;AAED,qBAAa,0BAA2B,SAAQ,YAAY,CAAC,4BAA4B,CAAC;IACxF,OAAO,CAAC,GAAG,CAAc;gBAEb,MAAM,EAAE,uBAAuB;IAK3C;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;;OAGG;IACG,MAAM,CACV,OAAO,EAAE,iBAAiB,GACzB,OAAO,CAAC,4BAA4B,CAAC;IAyIxC;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAyB9B;;OAEG;YACW,sBAAsB;IAuBpC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAsB/B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwC7B;;OAEG;YACW,mBAAmB;IAiCjC;;;OAGG;IACH,OAAO,CAAC,2BAA2B;IAiDnC;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAkEnC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAS7B;;OAEG;YACW,wBAAwB;IA4GtC;;OAEG;YACW,uBAAuB;IA2FrC;;OAEG;YACW,4BAA4B;IAoD1C,OAAO,CAAC,yBAAyB;IAwGjC,OAAO,CAAC,uBAAuB;IAqB/B,OAAO,CAAC,sBAAsB;IA0B9B,OAAO,CAAC,qBAAqB;IAgC7B,OAAO,CAAC,oBAAoB;IA8E5B;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoC3B;;OAEG;IACH,OAAO,CAAC,uBAAuB;CAqEhC"}
@@ -587,6 +587,36 @@ export class ProtocolComplianceAssessor extends BaseAssessor {
587
587
  // Legacy compatibility methods (from MCPSpecComplianceAssessor)
588
588
  // ============================================================================
589
589
  assessTransportCompliance(context) {
590
+ // Issue #172: Check source-based transport detection first
591
+ // This fixes incorrect FAIL for valid stdio servers without serverInfo metadata
592
+ if (context.transportDetection?.supportsStdio) {
593
+ return {
594
+ supportsStreamableHTTP: context.transportDetection.supportsHTTP,
595
+ deprecatedSSE: context.transportDetection.supportsSSE,
596
+ transportValidation: "passed",
597
+ supportsStdio: true,
598
+ supportsSSE: context.transportDetection.supportsSSE,
599
+ confidence: context.transportDetection.confidence,
600
+ detectionMethod: "source-code-analysis",
601
+ requiresManualCheck: false,
602
+ transportEvidence: context.transportDetection.evidence.map((e) => `${e.source}: ${e.detail}`),
603
+ };
604
+ }
605
+ // Also check HTTP-only detection (no serverInfo but HTTP transport detected)
606
+ if (context.transportDetection?.supportsHTTP &&
607
+ !context.transportDetection?.supportsStdio) {
608
+ return {
609
+ supportsStreamableHTTP: true,
610
+ deprecatedSSE: context.transportDetection.supportsSSE,
611
+ transportValidation: "passed",
612
+ supportsStdio: false,
613
+ supportsSSE: context.transportDetection.supportsSSE,
614
+ confidence: context.transportDetection.confidence,
615
+ detectionMethod: "source-code-analysis",
616
+ requiresManualCheck: false,
617
+ transportEvidence: context.transportDetection.evidence.map((e) => `${e.source}: ${e.detail}`),
618
+ };
619
+ }
590
620
  if (!context.serverInfo) {
591
621
  return {
592
622
  supportsStreamableHTTP: false,
@@ -1 +1 @@
1
- {"version":3,"file":"SecurityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/SecurityAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAiB9D,OAAO,EACL,gBAAgB,EAGjB,MAAM,yBAAyB,CAAC;AAEjC,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,YAAY,CAAiC;IAErD;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI;IAStD;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;OAGG;YACW,0BAA0B;gBAwBtC,MAAM,EAAE,OAAO,8BAA8B,EAAE,uBAAuB;IAwClE,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA8PrE;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoC7B;;OAEG;YACW,+BAA+B;IAiC7C;;;OAGG;YACW,yBAAyB;IA0CvC;;;;;;;OAOG;YACW,yBAAyB;IAmFvC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAYjC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAkEnC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;CAgDnC"}
1
+ {"version":3,"file":"SecurityAssessor.d.ts","sourceRoot":"","sources":["../../../../src/services/assessment/modules/SecurityAssessor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EACL,kBAAkB,EAInB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAiB9D,OAAO,EACL,gBAAgB,EAGjB,MAAM,yBAAyB,CAAC;AAEjC,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,OAAO,CAAC,aAAa,CAAwB;IAC7C,OAAO,CAAC,gBAAgB,CAA2B;IACnD,OAAO,CAAC,oBAAoB,CAAuB;IACnD,OAAO,CAAC,WAAW,CAAuB;IAC1C,OAAO,CAAC,YAAY,CAAiC;IAErD;;;OAGG;IACH,eAAe,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI,GAAG,IAAI;IAStD;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAOjC;;;OAGG;YACW,0BAA0B;gBAwBtC,MAAM,EAAE,OAAO,8BAA8B,EAAE,uBAAuB;IAwClE,MAAM,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAyQrE;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAoC7B;;OAEG;YACW,+BAA+B;IAiC7C;;;OAGG;YACW,yBAAyB;IA0CvC;;;;;;;OAOG;YACW,yBAAyB;IAmFvC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAYjC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IA0B/B;;OAEG;IACH,OAAO,CAAC,2BAA2B;IAkEnC;;;OAGG;IACH,OAAO,CAAC,0BAA0B;CAgDnC"}
@@ -101,6 +101,12 @@ export class SecurityAssessor extends BaseAssessor {
101
101
  async assess(context) {
102
102
  // Select tools for testing first
103
103
  const toolsToTest = this.selectToolsForTesting(context.tools);
104
+ // Issue #170: Set tool annotations context for severity adjustment
105
+ // This enables annotation-aware false positive reduction for read-only servers
106
+ if (!context.toolAnnotationsContext) {
107
+ this.logger.warn("No tool annotations context provided - severity adjustment disabled");
108
+ }
109
+ this.payloadTester.setToolAnnotationsContext(context.toolAnnotationsContext);
104
110
  // Run universal security testing via extracted payload tester
105
111
  const allTests = await this.payloadTester.runUniversalSecurityTests(toolsToTest, context.callTool, context.onProgress);
106
112
  // Separate connection errors from valid tests
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Annotation-Aware Severity Adjustment
3
+ *
4
+ * Reduces false positives by considering tool annotations when scoring
5
+ * vulnerability severity.
6
+ *
7
+ * Issue #170: Security module should consider tool annotations to reduce
8
+ * false positives for read-only servers.
9
+ *
10
+ * @module securityTests/AnnotationAwareSeverity
11
+ */
12
+ import type { SecurityAnnotations, SecurityRiskLevel } from "../../../../lib/assessment/coreTypes.js";
13
+ /**
14
+ * Result of annotation-aware severity adjustment.
15
+ */
16
+ export interface SeverityAdjustment {
17
+ /** Adjusted risk level after considering annotations */
18
+ adjustedRiskLevel: SecurityRiskLevel;
19
+ /** Whether an adjustment was made */
20
+ wasAdjusted: boolean;
21
+ /** Reason for adjustment (human-readable) */
22
+ adjustmentReason?: string;
23
+ /** Original risk level before adjustment */
24
+ originalRiskLevel: SecurityRiskLevel;
25
+ }
26
+ /**
27
+ * Adjust vulnerability severity based on tool annotations.
28
+ *
29
+ * This function implements the false positive reduction logic from Issue #170.
30
+ * Read-only tools (readOnlyHint=true) have execution-type vulnerabilities
31
+ * downgraded to LOW, and closed-world tools (openWorldHint=false) have
32
+ * exfiltration-type vulnerabilities downgraded to LOW.
33
+ *
34
+ * @param attackName - Name of the attack pattern (e.g., "Command Injection")
35
+ * @param originalRiskLevel - Original risk level from payload definition
36
+ * @param toolAnnotations - Extracted annotations for this specific tool
37
+ * @param serverIsReadOnly - Whether ALL server tools are read-only
38
+ * @param serverIsClosed - Whether ALL server tools are closed-world
39
+ * @returns SeverityAdjustment with potentially adjusted risk level
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const adjustment = adjustSeverityForAnnotations(
44
+ * "Command Injection",
45
+ * "HIGH",
46
+ * { readOnlyHint: true, source: "mcp" },
47
+ * true,
48
+ * false
49
+ * );
50
+ * // adjustment.wasAdjusted === true
51
+ * // adjustment.adjustedRiskLevel === "LOW"
52
+ * ```
53
+ */
54
+ export declare function adjustSeverityForAnnotations(attackName: string, originalRiskLevel: SecurityRiskLevel, toolAnnotations: SecurityAnnotations | undefined, serverIsReadOnly: boolean, serverIsClosed: boolean): SeverityAdjustment;
55
+ //# sourceMappingURL=AnnotationAwareSeverity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnnotationAwareSeverity.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/AnnotationAwareSeverity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AA+BpC;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,wDAAwD;IACxD,iBAAiB,EAAE,iBAAiB,CAAC;IACrC,qCAAqC;IACrC,WAAW,EAAE,OAAO,CAAC;IACrB,6CAA6C;IAC7C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,4CAA4C;IAC5C,iBAAiB,EAAE,iBAAiB,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,4BAA4B,CAC1C,UAAU,EAAE,MAAM,EAClB,iBAAiB,EAAE,iBAAiB,EACpC,eAAe,EAAE,mBAAmB,GAAG,SAAS,EAChD,gBAAgB,EAAE,OAAO,EACzB,cAAc,EAAE,OAAO,GACtB,kBAAkB,CA0DpB"}
@@ -0,0 +1,135 @@
1
+ /**
2
+ * Annotation-Aware Severity Adjustment
3
+ *
4
+ * Reduces false positives by considering tool annotations when scoring
5
+ * vulnerability severity.
6
+ *
7
+ * Issue #170: Security module should consider tool annotations to reduce
8
+ * false positives for read-only servers.
9
+ *
10
+ * @module securityTests/AnnotationAwareSeverity
11
+ */
12
+ /**
13
+ * Attack patterns that should be downgraded for read-only tools.
14
+ * These involve code/command execution which read-only tools cannot perform.
15
+ */
16
+ const EXECUTION_TYPE_ATTACKS = [
17
+ "Command Injection", // RCE via shell commands
18
+ "Calculator Injection", // Code evaluation via calculator
19
+ "Code Execution", // Direct code execution
20
+ "Path Traversal", // File system modification
21
+ "Cross-Tool State Bypass", // State manipulation attacks
22
+ "Chained Exploitation", // Multi-tool execution chains
23
+ "Tool Output Injection", // Output tampering
24
+ "Nested Injection", // Recursive injection attacks
25
+ "Auth Bypass", // Authentication manipulation
26
+ "Session Management", // Session state modification
27
+ ];
28
+ /**
29
+ * Attack patterns that should be downgraded for closed-world tools.
30
+ * These involve external network access which closed-world tools don't have.
31
+ */
32
+ const EXFILTRATION_TYPE_ATTACKS = [
33
+ "Indirect Prompt Injection", // External content injection
34
+ "Data Exfiltration", // Data leakage to external services
35
+ "Token Theft", // Credential exfiltration
36
+ "Secret Leakage", // Sensitive data exposure
37
+ "SSRF", // Server-side request forgery
38
+ ];
39
+ /**
40
+ * Adjust vulnerability severity based on tool annotations.
41
+ *
42
+ * This function implements the false positive reduction logic from Issue #170.
43
+ * Read-only tools (readOnlyHint=true) have execution-type vulnerabilities
44
+ * downgraded to LOW, and closed-world tools (openWorldHint=false) have
45
+ * exfiltration-type vulnerabilities downgraded to LOW.
46
+ *
47
+ * @param attackName - Name of the attack pattern (e.g., "Command Injection")
48
+ * @param originalRiskLevel - Original risk level from payload definition
49
+ * @param toolAnnotations - Extracted annotations for this specific tool
50
+ * @param serverIsReadOnly - Whether ALL server tools are read-only
51
+ * @param serverIsClosed - Whether ALL server tools are closed-world
52
+ * @returns SeverityAdjustment with potentially adjusted risk level
53
+ *
54
+ * @example
55
+ * ```typescript
56
+ * const adjustment = adjustSeverityForAnnotations(
57
+ * "Command Injection",
58
+ * "HIGH",
59
+ * { readOnlyHint: true, source: "mcp" },
60
+ * true,
61
+ * false
62
+ * );
63
+ * // adjustment.wasAdjusted === true
64
+ * // adjustment.adjustedRiskLevel === "LOW"
65
+ * ```
66
+ */
67
+ export function adjustSeverityForAnnotations(attackName, originalRiskLevel, toolAnnotations, serverIsReadOnly, serverIsClosed) {
68
+ // Check if we have valid per-tool annotations
69
+ const hasValidAnnotations = toolAnnotations && toolAnnotations.source !== "none";
70
+ // Check 1: Per-tool read-only for execution-type attacks
71
+ // If tool declares readOnlyHint=true, it cannot execute commands
72
+ if (hasValidAnnotations && toolAnnotations.readOnlyHint === true) {
73
+ if (isExecutionTypeAttack(attackName)) {
74
+ return {
75
+ adjustedRiskLevel: "LOW",
76
+ wasAdjusted: true,
77
+ adjustmentReason: `Tool has readOnlyHint=true; ${attackName} downgraded from ${originalRiskLevel} to LOW (cannot execute)`,
78
+ originalRiskLevel,
79
+ };
80
+ }
81
+ }
82
+ // Check 2: Per-tool closed-world for exfiltration-type attacks
83
+ // If tool declares openWorldHint=false, it cannot access external resources
84
+ if (hasValidAnnotations && toolAnnotations.openWorldHint === false) {
85
+ if (isExfiltrationType(attackName)) {
86
+ return {
87
+ adjustedRiskLevel: "LOW",
88
+ wasAdjusted: true,
89
+ adjustmentReason: `Tool has openWorldHint=false; ${attackName} downgraded from ${originalRiskLevel} to LOW (no external access)`,
90
+ originalRiskLevel,
91
+ };
92
+ }
93
+ }
94
+ // Check 3: Server-level read-only flag provides additional context
95
+ // Even if specific tool annotation is missing, server-level flag applies
96
+ if (serverIsReadOnly && isExecutionTypeAttack(attackName)) {
97
+ return {
98
+ adjustedRiskLevel: "LOW",
99
+ wasAdjusted: true,
100
+ adjustmentReason: `Server is 100% read-only; ${attackName} downgraded from ${originalRiskLevel} to LOW`,
101
+ originalRiskLevel,
102
+ };
103
+ }
104
+ // Check 4: Server-level closed flag
105
+ if (serverIsClosed && isExfiltrationType(attackName)) {
106
+ return {
107
+ adjustedRiskLevel: "LOW",
108
+ wasAdjusted: true,
109
+ adjustmentReason: `Server is 100% closed-world; ${attackName} downgraded from ${originalRiskLevel} to LOW`,
110
+ originalRiskLevel,
111
+ };
112
+ }
113
+ // No adjustment needed
114
+ return {
115
+ adjustedRiskLevel: originalRiskLevel,
116
+ wasAdjusted: false,
117
+ originalRiskLevel,
118
+ };
119
+ }
120
+ /**
121
+ * Check if attack name matches execution-type patterns.
122
+ * Only checks if attackName contains the pattern (not bidirectional)
123
+ * to prevent security bypass (e.g., "command" matching "Command Injection").
124
+ */
125
+ function isExecutionTypeAttack(attackName) {
126
+ return EXECUTION_TYPE_ATTACKS.some((pattern) => attackName.toLowerCase().includes(pattern.toLowerCase()));
127
+ }
128
+ /**
129
+ * Check if attack name matches exfiltration-type patterns.
130
+ * Only checks if attackName contains the pattern (not bidirectional)
131
+ * to prevent security bypass.
132
+ */
133
+ function isExfiltrationType(attackName) {
134
+ return EXFILTRATION_TYPE_ATTACKS.some((pattern) => attackName.toLowerCase().includes(pattern.toLowerCase()));
135
+ }
@@ -34,6 +34,12 @@ export declare class SafeResponseDetector {
34
34
  * Check if response is an HTTP error (Issue #26)
35
35
  */
36
36
  isHttpErrorResponse(responseText: string): boolean;
37
+ /**
38
+ * Check if response is an AppleScript syntax error (Issue #175)
39
+ * These errors should not be flagged as XXE vulnerabilities even when
40
+ * the XXE payload is echoed back in the error message.
41
+ */
42
+ isAppleScriptSyntaxError(responseText: string): boolean;
37
43
  /**
38
44
  * Check if response is just reflection (safe)
39
45
  * Two-layer defense: Match reflection patterns, verify NO execution evidence
@@ -1 +1 @@
1
- {"version":3,"file":"SafeResponseDetector.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/SafeResponseDetector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AAgBjF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,iBAAiB,CAA4B;;IAMrD;;OAEG;IACH,oBAAoB,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;IAQzE;;OAEG;IACH,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIlD;;;;;;OAMG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IA8EnD;;OAEG;IACH,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIrD;;OAEG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIjD;;OAEG;IACH,qBAAqB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,OAAO;IA0CrE;;OAEG;IACH,sBAAsB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM;CAUtE"}
1
+ {"version":3,"file":"SafeResponseDetector.d.ts","sourceRoot":"","sources":["../../../../../src/services/assessment/modules/securityTests/SafeResponseDetector.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,2BAA2B,EAAE,MAAM,oCAAoC,CAAC;AAiBjF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,iBAAiB,CAA4B;;IAMrD;;OAEG;IACH,oBAAoB,CAAC,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO;IAQzE;;OAEG;IACH,mBAAmB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIlD;;;;OAIG;IACH,wBAAwB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIvD;;;;;;OAMG;IACH,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IA8EnD;;OAEG;IACH,sBAAsB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIrD;;OAEG;IACH,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO;IAIjD;;OAEG;IACH,qBAAqB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,OAAO;IA0CrE;;OAEG;IACH,sBAAsB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM;CAUtE"}
@@ -5,7 +5,7 @@
5
5
  * Extracted from SecurityResponseAnalyzer.ts (Issue #53)
6
6
  * Handles: MCP validation, HTTP errors, reflection detection, validation rejection
7
7
  */
8
- import { VALIDATION_ERROR_PATTERNS, STATUS_PATTERNS, REFLECTION_PATTERNS, SEARCH_RESULT_PATTERNS, CREATION_PATTERNS, TEXT_REJECTION_PATTERNS, RESULT_REJECTION_PATTERNS, isHttpError, matchesAny, hasLLMInjectionMarkers, hasOutputInjectionVulnerability, } from "./SecurityPatternLibrary.js";
8
+ import { VALIDATION_ERROR_PATTERNS, STATUS_PATTERNS, REFLECTION_PATTERNS, SEARCH_RESULT_PATTERNS, CREATION_PATTERNS, TEXT_REJECTION_PATTERNS, RESULT_REJECTION_PATTERNS, isHttpError, matchesAny, hasLLMInjectionMarkers, hasOutputInjectionVulnerability, isAppleScriptSyntaxError as isAppleScriptSyntaxErrorPattern, } from "./SecurityPatternLibrary.js";
9
9
  import { ExecutionArtifactDetector } from "./ExecutionArtifactDetector.js";
10
10
  /**
11
11
  * Detects safe response patterns indicating proper tool behavior
@@ -30,6 +30,14 @@ export class SafeResponseDetector {
30
30
  isHttpErrorResponse(responseText) {
31
31
  return isHttpError(responseText);
32
32
  }
33
+ /**
34
+ * Check if response is an AppleScript syntax error (Issue #175)
35
+ * These errors should not be flagged as XXE vulnerabilities even when
36
+ * the XXE payload is echoed back in the error message.
37
+ */
38
+ isAppleScriptSyntaxError(responseText) {
39
+ return isAppleScriptSyntaxErrorPattern(responseText);
40
+ }
33
41
  /**
34
42
  * Check if response is just reflection (safe)
35
43
  * Two-layer defense: Match reflection patterns, verify NO execution evidence
@@ -133,6 +133,26 @@ export declare const PERMANENT_ERROR_PATTERNS: readonly [RegExp, RegExp, RegExp,
133
133
  * @returns true if error is transient and should be retried
134
134
  */
135
135
  export declare function isTransientErrorPattern(text: string): boolean;
136
+ /**
137
+ * Issue #175: AppleScript syntax error patterns to exclude from XXE detection
138
+ *
139
+ * AppleScript errors can trigger false positives when:
140
+ * 1. The tool returns an AppleScript syntax error (e.g., -2750 duplicate parameter)
141
+ * 2. The XXE payload is echoed back in the error message
142
+ * 3. XXE evidence patterns match "parameter" + "entity" combination
143
+ *
144
+ * These patterns detect AppleScript-specific errors by:
145
+ * - Error code ranges (-27xx, -25xx are AppleScript domain)
146
+ * - AppleScript-specific syntax error messages
147
+ * - Common AppleScript error patterns
148
+ */
149
+ export declare const APPLESCRIPT_SYNTAX_ERROR_PATTERNS: RegExp[];
150
+ /**
151
+ * Check if error text indicates an AppleScript syntax error (Issue #175)
152
+ * @param text Error message or response text
153
+ * @returns true if error is an AppleScript syntax error
154
+ */
155
+ export declare function isAppleScriptSyntaxError(text: string): boolean;
136
156
  /**
137
157
  * Status patterns indicating safe response handling
138
158
  * Used by: isReflectionResponse()