@mcp-shark/mcp-shark 1.5.13 → 1.7.2

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 (158) hide show
  1. package/README.md +482 -56
  2. package/bin/mcp-shark.js +146 -52
  3. package/core/cli/AutoFixEngine.js +93 -0
  4. package/core/cli/ConfigScanner.js +193 -0
  5. package/core/cli/DataLoader.js +200 -0
  6. package/core/cli/DeclarativeRuleEngine.js +363 -0
  7. package/core/cli/DoctorCommand.js +218 -0
  8. package/core/cli/FixHandlers.js +222 -0
  9. package/core/cli/HtmlReportGenerator.js +203 -0
  10. package/core/cli/IdeConfigPaths.js +175 -0
  11. package/core/cli/ListCommand.js +255 -0
  12. package/core/cli/LockCommand.js +164 -0
  13. package/core/cli/LockDiffEngine.js +152 -0
  14. package/core/cli/RuleRegistryConfig.js +131 -0
  15. package/core/cli/ScanCommand.js +244 -0
  16. package/core/cli/ScanService.js +200 -0
  17. package/core/cli/SecretDetector.js +92 -0
  18. package/core/cli/SharkScoreCalculator.js +109 -0
  19. package/core/cli/ToolClassifications.js +51 -0
  20. package/core/cli/ToxicFlowAnalyzer.js +212 -0
  21. package/core/cli/UpdateCommand.js +188 -0
  22. package/core/cli/WalkthroughGenerator.js +195 -0
  23. package/core/cli/WatchCommand.js +129 -0
  24. package/core/cli/YamlRuleEngine.js +197 -0
  25. package/core/cli/data/rule-packs/aauth-visibility.json +117 -0
  26. package/core/cli/data/rule-packs/agentic-security-2026.json +180 -0
  27. package/core/cli/data/rule-packs/general-security.json +173 -0
  28. package/core/cli/data/rule-packs/owasp-mcp-2026.json +244 -0
  29. package/core/cli/data/rule-packs/toxic-flow-heuristics.json +21 -0
  30. package/core/cli/data/rule-sources.json +5 -0
  31. package/core/cli/data/secret-patterns.json +18 -0
  32. package/core/cli/data/tool-classifications.json +111 -0
  33. package/core/cli/data/toxic-flow-rules.json +47 -0
  34. package/core/cli/index.js +23 -0
  35. package/core/cli/output/Banner.js +52 -0
  36. package/core/cli/output/Formatter.js +183 -0
  37. package/core/cli/output/JsonFormatter.js +106 -0
  38. package/core/cli/output/index.js +16 -0
  39. package/core/cli/secureRegistryFetch.js +157 -0
  40. package/core/cli/symbols.js +16 -0
  41. package/core/configs/environment.js +3 -1
  42. package/core/configs/index.js +3 -64
  43. package/core/container/DependencyContainer.js +4 -1
  44. package/core/mcp-server/index.js +4 -1
  45. package/core/mcp-server/server/external/all.js +10 -3
  46. package/core/mcp-server/server/external/config.js +62 -5
  47. package/core/models/RequestFilters.js +3 -0
  48. package/core/repositories/PacketRepository.js +16 -0
  49. package/core/services/AuditService.js +2 -0
  50. package/core/services/ConfigService.js +9 -1
  51. package/core/services/ConfigTransformService.js +34 -2
  52. package/core/services/RequestService.js +58 -5
  53. package/core/services/ServerManagementService.js +59 -4
  54. package/core/services/security/StaticRulesService.js +69 -13
  55. package/core/services/security/TrafficAnalysisService.js +19 -1
  56. package/core/services/security/TrafficToxicFlowService.js +154 -0
  57. package/core/services/security/aauthGraph.js +199 -0
  58. package/core/services/security/aauthParser.js +274 -0
  59. package/core/services/security/aauthSelfTest.js +346 -0
  60. package/core/services/security/index.js +2 -1
  61. package/core/services/security/rules/index.js +25 -59
  62. package/core/services/security/rules/scans/configPermissions.js +91 -0
  63. package/core/services/security/rules/scans/duplicateToolNames.js +85 -0
  64. package/core/services/security/rules/scans/insecureTransport.js +148 -0
  65. package/core/services/security/rules/scans/missingContainment.js +123 -0
  66. package/core/services/security/rules/scans/shellEnvInjection.js +101 -0
  67. package/core/services/security/rules/scans/unsafeDefaults.js +99 -0
  68. package/core/services/security/toolsListFromTrafficParser.js +70 -0
  69. package/core/tui/App.js +144 -0
  70. package/core/tui/FindingsPanel.js +115 -0
  71. package/core/tui/FixPanel.js +132 -0
  72. package/core/tui/Header.js +51 -0
  73. package/core/tui/HelpBar.js +42 -0
  74. package/core/tui/ServersPanel.js +109 -0
  75. package/core/tui/ToxicFlowsPanel.js +100 -0
  76. package/core/tui/h.js +8 -0
  77. package/core/tui/index.js +11 -0
  78. package/core/tui/render.js +22 -0
  79. package/package.json +24 -16
  80. package/ui/dist/assets/index-D6zDrtMV.js +81 -0
  81. package/ui/dist/index.html +1 -1
  82. package/ui/server/controllers/AauthController.js +279 -0
  83. package/ui/server/controllers/RequestController.js +12 -1
  84. package/ui/server/controllers/SecurityFindingsController.js +46 -1
  85. package/ui/server/routes/aauth.js +18 -0
  86. package/ui/server/routes/requests.js +8 -1
  87. package/ui/server/routes/security.js +5 -1
  88. package/ui/server/setup.js +224 -6
  89. package/ui/server/swagger/paths/components.js +55 -0
  90. package/ui/server/swagger/paths/securityTrafficFlows.js +59 -0
  91. package/ui/server/swagger/paths.js +2 -2
  92. package/ui/server/swagger/swagger.js +5 -2
  93. package/ui/server.js +1 -1
  94. package/ui/src/App.jsx +26 -52
  95. package/ui/src/PacketFilters.jsx +31 -1
  96. package/ui/src/PacketList.jsx +2 -2
  97. package/ui/src/Security.jsx +10 -0
  98. package/ui/src/TabNavigation.jsx +8 -0
  99. package/ui/src/components/AAuthBadge.jsx +92 -0
  100. package/ui/src/components/AauthExplorer/AauthExplorerGraph.jsx +231 -0
  101. package/ui/src/components/AauthExplorer/AauthExplorerView.jsx +387 -0
  102. package/ui/src/components/AauthExplorer/NodeDetailPanel.jsx +272 -0
  103. package/ui/src/components/App/ActionMenu.jsx +4 -31
  104. package/ui/src/components/App/ApiDocsButton.jsx +0 -1
  105. package/ui/src/components/App/ShutdownButton.jsx +0 -1
  106. package/ui/src/components/App/useAppState.js +19 -26
  107. package/ui/src/components/DetailsTab/AAuthIdentitySection.jsx +119 -0
  108. package/ui/src/components/DetailsTab/RequestDetailsSection.jsx +2 -0
  109. package/ui/src/components/DetailsTab/ResponseDetailsSection.jsx +2 -0
  110. package/ui/src/components/DetectedPathsList.jsx +1 -5
  111. package/ui/src/components/FileInput.jsx +0 -1
  112. package/ui/src/components/PacketFilters/AAuthPostureFilter.jsx +81 -0
  113. package/ui/src/components/RequestRow/RequestRowMain.jsx +7 -1
  114. package/ui/src/components/Security/AAuthPosturePanel.jsx +360 -0
  115. package/ui/src/components/Security/ScannerContent.jsx +33 -1
  116. package/ui/src/components/Security/TrafficToxicFlowsPanel.jsx +253 -0
  117. package/ui/src/components/Security/securityApi.js +15 -0
  118. package/ui/src/components/Security/useSecurity.js +60 -3
  119. package/ui/src/components/ServerControl.jsx +0 -1
  120. package/ui/src/components/TabNavigation/DesktopTabs.jsx +0 -11
  121. package/ui/src/components/TabNavigationIcons.jsx +5 -0
  122. package/ui/src/components/ViewModeTabs.jsx +0 -1
  123. package/ui/src/utils/animations.js +26 -9
  124. package/core/services/security/rules/scans/agentic01GoalHijack.js +0 -130
  125. package/core/services/security/rules/scans/agentic02ToolMisuse.js +0 -129
  126. package/core/services/security/rules/scans/agentic03IdentityAbuse.js +0 -130
  127. package/core/services/security/rules/scans/agentic04SupplyChain.js +0 -130
  128. package/core/services/security/rules/scans/agentic06MemoryPoisoning.js +0 -130
  129. package/core/services/security/rules/scans/agentic07InsecureCommunication.js +0 -135
  130. package/core/services/security/rules/scans/agentic08CascadingFailures.js +0 -135
  131. package/core/services/security/rules/scans/agentic09TrustExploitation.js +0 -135
  132. package/core/services/security/rules/scans/agentic10RogueAgent.js +0 -130
  133. package/core/services/security/rules/scans/hardcodedSecrets.js +0 -130
  134. package/core/services/security/rules/scans/mcp01TokenMismanagement.js +0 -127
  135. package/core/services/security/rules/scans/mcp02ScopeCreep.js +0 -130
  136. package/core/services/security/rules/scans/mcp03ToolPoisoning.js +0 -132
  137. package/core/services/security/rules/scans/mcp04SupplyChain.js +0 -131
  138. package/core/services/security/rules/scans/mcp06PromptInjection.js +0 -200
  139. package/core/services/security/rules/scans/mcp07InsufficientAuth.js +0 -130
  140. package/core/services/security/rules/scans/mcp08LackAudit.js +0 -129
  141. package/core/services/security/rules/scans/mcp09ShadowServers.js +0 -129
  142. package/core/services/security/rules/scans/mcp10ContextInjection.js +0 -130
  143. package/ui/dist/assets/index-CiCSDYf-.js +0 -97
  144. package/ui/server/routes/help.js +0 -44
  145. package/ui/server/swagger/paths/help.js +0 -82
  146. package/ui/src/HelpGuide/HelpGuideContent.jsx +0 -118
  147. package/ui/src/HelpGuide/HelpGuideFooter.jsx +0 -59
  148. package/ui/src/HelpGuide/HelpGuideHeader.jsx +0 -57
  149. package/ui/src/HelpGuide.jsx +0 -78
  150. package/ui/src/IntroTour.jsx +0 -154
  151. package/ui/src/components/App/HelpButton.jsx +0 -90
  152. package/ui/src/components/TourOverlay.jsx +0 -117
  153. package/ui/src/components/TourTooltip/TourTooltipButtons.jsx +0 -120
  154. package/ui/src/components/TourTooltip/TourTooltipHeader.jsx +0 -71
  155. package/ui/src/components/TourTooltip/TourTooltipIcons.jsx +0 -54
  156. package/ui/src/components/TourTooltip/useTooltipPosition.js +0 -135
  157. package/ui/src/components/TourTooltip.jsx +0 -91
  158. package/ui/src/config/tourSteps.jsx +0 -140
@@ -1,130 +0,0 @@
1
- import { convertPacketFinding, createRuleAdapter } from '../utils/adapter.js';
2
- import { packetToText, promptToText, resourceToText, toolToText } from '../utils/text.js';
3
-
4
- const RULE_ID = 'asi10-rogue-agent';
5
- const OWASP_ID = 'ASI10';
6
- const RECOMMENDATION =
7
- 'Implement agent registration and approval processes. Monitor for unauthorized agent creation. Enforce agent lifecycle management.';
8
-
9
- const ROGUE_AGENT_PATTERNS = [
10
- /(?:rogue|unauthorized|unapproved|malicious|harmful)\s+(?:agent|bot|automation|system)/i,
11
- /(?:unauthorized|unapproved|unmanaged)\s+(?:agent|bot)\s+(?:creation|deployment|execution|activation)/i,
12
- /(?:bypass|circumvent|avoid)\s+(?:approval|authorization|review|governance)\s+(?:for|to\s+create|to\s+deploy)/i,
13
- /(?:hidden|concealed|undocumented|unregistered)\s+(?:agent|bot|automation)/i,
14
- /(?:self-replicating|self-propagating|autonomous)\s+(?:agent|bot)\s+(?:without|lacking)/i,
15
- ];
16
-
17
- function scanText(text) {
18
- if (!text) {
19
- return null;
20
- }
21
- const matches = [];
22
- for (const pattern of ROGUE_AGENT_PATTERNS) {
23
- const match = text.match(pattern);
24
- if (match) {
25
- matches.push(match[0]);
26
- }
27
- }
28
- return matches.length > 0 ? matches : null;
29
- }
30
-
31
- function buildReason(entity, matches) {
32
- return `Potential rogue agent indicators in ${entity}: ${matches.join(', ')}`;
33
- }
34
-
35
- export function scanAgentic10RogueAgent(mcpData = {}) {
36
- const results = {
37
- toolFindings: [],
38
- resourceFindings: [],
39
- promptFindings: [],
40
- notablePatterns: [],
41
- recommendations: [RECOMMENDATION],
42
- };
43
-
44
- for (const tool of mcpData.tools || []) {
45
- const matches = scanText(toolToText(tool));
46
- if (matches) {
47
- results.toolFindings.push({
48
- issueType: 'Rogue Agent',
49
- name: tool?.name || 'tool',
50
- severity: 'critical',
51
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
52
- tags: ['rogue-agent', 'unauthorized'],
53
- agenticCategory: OWASP_ID,
54
- safeUseNotes:
55
- 'Verify agent registration and approval status. Ensure all agents are properly managed and monitored.',
56
- });
57
- }
58
- }
59
-
60
- for (const resource of mcpData.resources || []) {
61
- const matches = scanText(resourceToText(resource));
62
- if (matches) {
63
- results.resourceFindings.push({
64
- issueType: 'Rogue Agent',
65
- uri: resource?.uri || resource?.name || 'resource',
66
- severity: 'critical',
67
- reasons: [
68
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
69
- ],
70
- tags: ['rogue-agent', 'unauthorized'],
71
- agenticCategory: OWASP_ID,
72
- });
73
- }
74
- }
75
-
76
- for (const prompt of mcpData.prompts || []) {
77
- const matches = scanText(promptToText(prompt));
78
- if (matches) {
79
- results.promptFindings.push({
80
- issueType: 'Rogue Agent',
81
- name: prompt?.name || 'prompt',
82
- severity: 'high',
83
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
84
- tags: ['rogue-agent', 'unauthorized'],
85
- agenticCategory: OWASP_ID,
86
- });
87
- }
88
- }
89
-
90
- return results;
91
- }
92
-
93
- const adapter = createRuleAdapter(scanAgentic10RogueAgent, RULE_ID, OWASP_ID, RECOMMENDATION);
94
-
95
- export const analyzeTool = adapter.analyzeTool;
96
- export const analyzePrompt = adapter.analyzePrompt;
97
- export const analyzeResource = adapter.analyzeResource;
98
-
99
- export function analyzePacket(packet) {
100
- const text = packetToText(packet);
101
- const matches = scanText(text);
102
- if (!matches) {
103
- return [];
104
- }
105
- return [
106
- convertPacketFinding(
107
- {
108
- issueType: 'Rogue Agent',
109
- severity: 'critical',
110
- title: 'Rogue Agent Pattern in Traffic',
111
- description: `Potential rogue agent indicators in packet: ${matches.join(', ')}`,
112
- evidence: matches[0]?.substring(0, 50) || '',
113
- },
114
- RULE_ID,
115
- OWASP_ID,
116
- RECOMMENDATION,
117
- packet
118
- ),
119
- ];
120
- }
121
-
122
- export const ruleMetadata = {
123
- id: RULE_ID,
124
- name: 'Rogue Agent Detection',
125
- owasp_id: OWASP_ID,
126
- severity: 'critical',
127
- description: 'Detects rogue agent vulnerabilities.',
128
- source: 'static',
129
- type: 'agentic-security',
130
- };
@@ -1,130 +0,0 @@
1
- import { SECRET_PATTERNS } from '../constants.js';
2
- import { convertPacketFinding, createRuleAdapter } from '../utils/adapter.js';
3
- import { packetToText, promptToText, resourceToText, toolToText } from '../utils/text.js';
4
-
5
- const RULE_ID = 'hardcoded-secrets';
6
- const OWASP_ID = 'SECRET';
7
- const RECOMMENDATION =
8
- 'Move secrets or API tokens to secure storage; never embed them directly in tool or resource metadata.';
9
-
10
- function redacted(value) {
11
- if (!value) {
12
- return '';
13
- }
14
- if (value.length <= 8) {
15
- return '***';
16
- }
17
- return `${value.slice(0, 4)}...${value.slice(-4)}`;
18
- }
19
-
20
- function scanText(text) {
21
- if (!text) {
22
- return null;
23
- }
24
- for (const pattern of SECRET_PATTERNS) {
25
- pattern.regex.lastIndex = 0;
26
- const match = text.match(pattern.regex);
27
- if (match) {
28
- return {
29
- type: pattern.type,
30
- sample: redacted(match[0]),
31
- };
32
- }
33
- }
34
- return null;
35
- }
36
-
37
- function buildReason(entity, secretInfo) {
38
- return `Potential ${secretInfo.type} secret leaked inside ${entity} (sample ${secretInfo.sample}).`;
39
- }
40
-
41
- export function scanHardcodedSecrets(mcpData = {}) {
42
- const results = {
43
- toolFindings: [],
44
- resourceFindings: [],
45
- promptFindings: [],
46
- notablePatterns: [],
47
- recommendations: [RECOMMENDATION],
48
- };
49
-
50
- for (const tool of mcpData.tools || []) {
51
- const info = scanText(toolToText(tool));
52
- if (info) {
53
- results.toolFindings.push({
54
- issueType: 'Hardcoded Secret',
55
- name: tool?.name || 'tool',
56
- severity: 'high',
57
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, info)],
58
- tags: ['secret'],
59
- safeUseNotes: 'Remove the leaked credential and rotate it immediately.',
60
- });
61
- }
62
- }
63
-
64
- for (const resource of mcpData.resources || []) {
65
- const info = scanText(resourceToText(resource));
66
- if (info) {
67
- results.resourceFindings.push({
68
- issueType: 'Hardcoded Secret',
69
- uri: resource?.uri || resource?.name || 'resource',
70
- severity: 'high',
71
- reasons: [buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, info)],
72
- tags: ['secret'],
73
- });
74
- }
75
- }
76
-
77
- for (const prompt of mcpData.prompts || []) {
78
- const info = scanText(promptToText(prompt));
79
- if (info) {
80
- results.promptFindings.push({
81
- issueType: 'Hardcoded Secret',
82
- name: prompt?.name || 'prompt',
83
- severity: 'medium',
84
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, info)],
85
- tags: ['secret'],
86
- });
87
- }
88
- }
89
-
90
- return results;
91
- }
92
-
93
- const adapter = createRuleAdapter(scanHardcodedSecrets, RULE_ID, OWASP_ID, RECOMMENDATION);
94
-
95
- export const analyzeTool = adapter.analyzeTool;
96
- export const analyzePrompt = adapter.analyzePrompt;
97
- export const analyzeResource = adapter.analyzeResource;
98
-
99
- export function analyzePacket(packet) {
100
- const text = packetToText(packet);
101
- const info = scanText(text);
102
- if (!info) {
103
- return [];
104
- }
105
- return [
106
- convertPacketFinding(
107
- {
108
- issueType: 'Hardcoded Secret',
109
- severity: 'high',
110
- title: 'Secret Detected in Traffic',
111
- description: `Potential ${info.type} secret in packet (sample ${info.sample}).`,
112
- evidence: info.sample,
113
- },
114
- RULE_ID,
115
- OWASP_ID,
116
- RECOMMENDATION,
117
- packet
118
- ),
119
- ];
120
- }
121
-
122
- export const ruleMetadata = {
123
- id: RULE_ID,
124
- name: 'Hardcoded Secrets Detection',
125
- owasp_id: OWASP_ID,
126
- severity: 'high',
127
- description: 'Detects hardcoded secrets and API tokens in metadata.',
128
- source: 'static',
129
- type: 'general-security',
130
- };
@@ -1,127 +0,0 @@
1
- import { SECRET_PATTERNS } from '../constants.js';
2
- import { convertPacketFinding, createRuleAdapter } from '../utils/adapter.js';
3
- import { packetToText, promptToText, resourceToText, toolToText } from '../utils/text.js';
4
-
5
- const RULE_ID = 'mcp01-token-mismanagement';
6
- const OWASP_ID = 'MCP01';
7
- const RECOMMENDATION =
8
- 'Move all tokens and secrets to secure storage (environment variables, secret managers). Never embed credentials in MCP server configurations.';
9
-
10
- function scanText(text) {
11
- if (!text) {
12
- return null;
13
- }
14
- const matches = [];
15
- for (const pattern of SECRET_PATTERNS) {
16
- pattern.regex.lastIndex = 0;
17
- const match = text.match(pattern.regex);
18
- if (match) {
19
- matches.push({ type: pattern.type, sample: match[0] });
20
- }
21
- }
22
- return matches.length > 0 ? matches : null;
23
- }
24
-
25
- function buildReason(entity, matches) {
26
- const types = matches.map((m) => m.type).join(', ');
27
- return `Token or secret exposure detected in ${entity}: ${types}`;
28
- }
29
-
30
- export function scanMCP01TokenMismanagement(mcpData = {}) {
31
- const results = {
32
- toolFindings: [],
33
- resourceFindings: [],
34
- promptFindings: [],
35
- notablePatterns: [],
36
- recommendations: [RECOMMENDATION],
37
- };
38
-
39
- for (const tool of mcpData.tools || []) {
40
- const matches = scanText(toolToText(tool));
41
- if (matches) {
42
- results.toolFindings.push({
43
- issueType: 'Token Mismanagement',
44
- name: tool?.name || 'tool',
45
- severity: 'high',
46
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
47
- tags: ['token-mismanagement', 'secret-exposure'],
48
- mcpCategory: OWASP_ID,
49
- safeUseNotes:
50
- 'Remove all tokens and secrets from tool metadata. Use secure storage mechanisms.',
51
- });
52
- }
53
- }
54
-
55
- for (const resource of mcpData.resources || []) {
56
- const matches = scanText(resourceToText(resource));
57
- if (matches) {
58
- results.resourceFindings.push({
59
- issueType: 'Token Mismanagement',
60
- uri: resource?.uri || resource?.name || 'resource',
61
- severity: 'high',
62
- reasons: [
63
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
64
- ],
65
- tags: ['token-mismanagement', 'secret-exposure'],
66
- mcpCategory: OWASP_ID,
67
- });
68
- }
69
- }
70
-
71
- for (const prompt of mcpData.prompts || []) {
72
- const matches = scanText(promptToText(prompt));
73
- if (matches) {
74
- results.promptFindings.push({
75
- issueType: 'Token Mismanagement',
76
- name: prompt?.name || 'prompt',
77
- severity: 'medium',
78
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
79
- tags: ['token-mismanagement', 'secret-exposure'],
80
- mcpCategory: OWASP_ID,
81
- });
82
- }
83
- }
84
-
85
- return results;
86
- }
87
-
88
- const adapter = createRuleAdapter(scanMCP01TokenMismanagement, RULE_ID, OWASP_ID, RECOMMENDATION);
89
-
90
- export const analyzeTool = adapter.analyzeTool;
91
- export const analyzePrompt = adapter.analyzePrompt;
92
- export const analyzeResource = adapter.analyzeResource;
93
-
94
- export function analyzePacket(packet) {
95
- const text = packetToText(packet);
96
- const matches = scanText(text);
97
- if (!matches) {
98
- return [];
99
- }
100
- const types = matches.map((m) => m.type).join(', ');
101
- return [
102
- convertPacketFinding(
103
- {
104
- issueType: 'Token Mismanagement',
105
- severity: 'high',
106
- title: 'Token/Secret Detected in Traffic',
107
- description: `Potential secret exposure in packet: ${types}`,
108
- evidence: matches[0]?.sample?.substring(0, 50) || '',
109
- },
110
- RULE_ID,
111
- OWASP_ID,
112
- RECOMMENDATION,
113
- packet
114
- ),
115
- ];
116
- }
117
-
118
- export const ruleMetadata = {
119
- id: RULE_ID,
120
- name: 'Token Mismanagement & Secret Exposure',
121
- owasp_id: OWASP_ID,
122
- severity: 'high',
123
- description:
124
- 'Detects hard-coded credentials, API keys, and secrets that could be exposed through prompt injection or compromised context.',
125
- source: 'static',
126
- type: 'owasp-mcp',
127
- };
@@ -1,130 +0,0 @@
1
- import { convertPacketFinding, createRuleAdapter } from '../utils/adapter.js';
2
- import { packetToText, promptToText, resourceToText, toolToText } from '../utils/text.js';
3
-
4
- const RULE_ID = 'mcp02-scope-creep';
5
- const OWASP_ID = 'MCP02';
6
- const RECOMMENDATION =
7
- 'Implement strict scope boundaries for tools. Monitor for unauthorized scope expansion and enforce least privilege principles.';
8
-
9
- const SCOPE_CREEP_PATTERNS = [
10
- /(?:expand|extend|increase|broaden|widen)\s+(?:scope|permission|access|capability|authority)/i,
11
- /(?:additional|extra|more|further)\s+(?:privilege|permission|access|right)/i,
12
- /(?:escalate|elevate|raise|upgrade)\s+(?:privilege|permission|access|level)/i,
13
- /(?:unrestricted|unlimited|full|complete|total)\s+(?:access|permission|privilege|control)/i,
14
- /(?:bypass|override|circumvent)\s+(?:restriction|limit|constraint|control)/i,
15
- ];
16
-
17
- function scanText(text) {
18
- if (!text) {
19
- return null;
20
- }
21
- const matches = [];
22
- for (const pattern of SCOPE_CREEP_PATTERNS) {
23
- const match = text.match(pattern);
24
- if (match) {
25
- matches.push(match[0]);
26
- }
27
- }
28
- return matches.length > 0 ? matches : null;
29
- }
30
-
31
- function buildReason(entity, matches) {
32
- return `Potential scope creep detected in ${entity}: ${matches.join(', ')}`;
33
- }
34
-
35
- export function scanMCP02ScopeCreep(mcpData = {}) {
36
- const results = {
37
- toolFindings: [],
38
- resourceFindings: [],
39
- promptFindings: [],
40
- notablePatterns: [],
41
- recommendations: [RECOMMENDATION],
42
- };
43
-
44
- for (const tool of mcpData.tools || []) {
45
- const matches = scanText(toolToText(tool));
46
- if (matches) {
47
- results.toolFindings.push({
48
- issueType: 'Scope Creep',
49
- name: tool?.name || 'tool',
50
- severity: 'medium',
51
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
52
- tags: ['scope-creep', 'privilege-escalation'],
53
- mcpCategory: OWASP_ID,
54
- safeUseNotes:
55
- 'Review tool scope boundaries. Ensure tools cannot expand their permissions beyond intended limits.',
56
- });
57
- }
58
- }
59
-
60
- for (const resource of mcpData.resources || []) {
61
- const matches = scanText(resourceToText(resource));
62
- if (matches) {
63
- results.resourceFindings.push({
64
- issueType: 'Scope Creep',
65
- uri: resource?.uri || resource?.name || 'resource',
66
- severity: 'medium',
67
- reasons: [
68
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
69
- ],
70
- tags: ['scope-creep', 'privilege-escalation'],
71
- mcpCategory: OWASP_ID,
72
- });
73
- }
74
- }
75
-
76
- for (const prompt of mcpData.prompts || []) {
77
- const matches = scanText(promptToText(prompt));
78
- if (matches) {
79
- results.promptFindings.push({
80
- issueType: 'Scope Creep',
81
- name: prompt?.name || 'prompt',
82
- severity: 'low',
83
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
84
- tags: ['scope-creep', 'privilege-escalation'],
85
- mcpCategory: OWASP_ID,
86
- });
87
- }
88
- }
89
-
90
- return results;
91
- }
92
-
93
- const adapter = createRuleAdapter(scanMCP02ScopeCreep, RULE_ID, OWASP_ID, RECOMMENDATION);
94
-
95
- export const analyzeTool = adapter.analyzeTool;
96
- export const analyzePrompt = adapter.analyzePrompt;
97
- export const analyzeResource = adapter.analyzeResource;
98
-
99
- export function analyzePacket(packet) {
100
- const text = packetToText(packet);
101
- const matches = scanText(text);
102
- if (!matches) {
103
- return [];
104
- }
105
- return [
106
- convertPacketFinding(
107
- {
108
- issueType: 'Scope Creep',
109
- severity: 'medium',
110
- title: 'Scope Creep Pattern in Traffic',
111
- description: `Potential scope creep in packet: ${matches.join(', ')}`,
112
- evidence: matches[0]?.substring(0, 50) || '',
113
- },
114
- RULE_ID,
115
- OWASP_ID,
116
- RECOMMENDATION,
117
- packet
118
- ),
119
- ];
120
- }
121
-
122
- export const ruleMetadata = {
123
- id: RULE_ID,
124
- name: 'Scope Creep Detection',
125
- owasp_id: OWASP_ID,
126
- severity: 'medium',
127
- description: 'Detects potential privilege escalation via scope creep in tool definitions.',
128
- source: 'static',
129
- type: 'owasp-mcp',
130
- };
@@ -1,132 +0,0 @@
1
- import { convertPacketFinding, createRuleAdapter } from '../utils/adapter.js';
2
- import { packetToText, promptToText, resourceToText, toolToText } from '../utils/text.js';
3
-
4
- const RULE_ID = 'mcp03-tool-poisoning';
5
- const OWASP_ID = 'MCP03';
6
- const RECOMMENDATION =
7
- 'Verify tool authenticity and integrity. Implement tool signing and verification mechanisms. Monitor for suspicious tool behavior.';
8
-
9
- const TOOL_POISONING_PATTERNS = [
10
- /(?:malicious|harmful|dangerous|exploit|attack|backdoor|trojan|virus)/i,
11
- /(?:unauthorized|illegitimate|fake|spoofed|forged|tampered)/i,
12
- /(?:steal|exfiltrate|leak|extract)\s+(?:data|information|credentials|secrets)/i,
13
- /(?:delete|remove|destroy|wipe|erase)\s+(?:file|data|information)/i,
14
- /(?:override|bypass|disable)\s+(?:security|protection|safeguard|control)/i,
15
- /(?:hidden|concealed|obfuscated|encoded)\s+(?:functionality|behavior|action)/i,
16
- ];
17
-
18
- function scanText(text) {
19
- if (!text) {
20
- return null;
21
- }
22
- const matches = [];
23
- for (const pattern of TOOL_POISONING_PATTERNS) {
24
- const match = text.match(pattern);
25
- if (match) {
26
- matches.push(match[0]);
27
- }
28
- }
29
- return matches.length > 0 ? matches : null;
30
- }
31
-
32
- function buildReason(entity, matches) {
33
- return `Potential tool poisoning indicators in ${entity}: ${matches.join(', ')}`;
34
- }
35
-
36
- export function scanMCP03ToolPoisoning(mcpData = {}) {
37
- const results = {
38
- toolFindings: [],
39
- resourceFindings: [],
40
- promptFindings: [],
41
- notablePatterns: [],
42
- recommendations: [RECOMMENDATION],
43
- };
44
-
45
- for (const tool of mcpData.tools || []) {
46
- const matches = scanText(toolToText(tool));
47
- if (matches) {
48
- results.toolFindings.push({
49
- issueType: 'Tool Poisoning',
50
- name: tool?.name || 'tool',
51
- severity: 'high',
52
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
53
- tags: ['tool-poisoning', 'malicious'],
54
- mcpCategory: OWASP_ID,
55
- is_potentially_poisoned: true,
56
- safeUseNotes:
57
- 'Review tool description and behavior carefully. Verify tool source and integrity before use.',
58
- });
59
- }
60
- }
61
-
62
- for (const resource of mcpData.resources || []) {
63
- const matches = scanText(resourceToText(resource));
64
- if (matches) {
65
- results.resourceFindings.push({
66
- issueType: 'Tool Poisoning',
67
- uri: resource?.uri || resource?.name || 'resource',
68
- severity: 'high',
69
- reasons: [
70
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
71
- ],
72
- tags: ['tool-poisoning', 'malicious'],
73
- mcpCategory: OWASP_ID,
74
- });
75
- }
76
- }
77
-
78
- for (const prompt of mcpData.prompts || []) {
79
- const matches = scanText(promptToText(prompt));
80
- if (matches) {
81
- results.promptFindings.push({
82
- issueType: 'Tool Poisoning',
83
- name: prompt?.name || 'prompt',
84
- severity: 'medium',
85
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
86
- tags: ['tool-poisoning', 'malicious'],
87
- mcpCategory: OWASP_ID,
88
- });
89
- }
90
- }
91
-
92
- return results;
93
- }
94
-
95
- const adapter = createRuleAdapter(scanMCP03ToolPoisoning, RULE_ID, OWASP_ID, RECOMMENDATION);
96
-
97
- export const analyzeTool = adapter.analyzeTool;
98
- export const analyzePrompt = adapter.analyzePrompt;
99
- export const analyzeResource = adapter.analyzeResource;
100
-
101
- export function analyzePacket(packet) {
102
- const text = packetToText(packet);
103
- const matches = scanText(text);
104
- if (!matches) {
105
- return [];
106
- }
107
- return [
108
- convertPacketFinding(
109
- {
110
- issueType: 'Tool Poisoning',
111
- severity: 'high',
112
- title: 'Tool Poisoning Pattern in Traffic',
113
- description: `Potential malicious pattern in packet: ${matches.join(', ')}`,
114
- evidence: matches[0]?.substring(0, 50) || '',
115
- },
116
- RULE_ID,
117
- OWASP_ID,
118
- RECOMMENDATION,
119
- packet
120
- ),
121
- ];
122
- }
123
-
124
- export const ruleMetadata = {
125
- id: RULE_ID,
126
- name: 'Tool Poisoning Detection',
127
- owasp_id: OWASP_ID,
128
- severity: 'high',
129
- description: 'Detects malicious patterns that could indicate tool poisoning attacks.',
130
- source: 'static',
131
- type: 'owasp-mcp',
132
- };