@mcp-shark/mcp-shark 1.5.13 → 1.6.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 (100) hide show
  1. package/README.md +396 -59
  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 +224 -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/agentic-security-2026.json +180 -0
  26. package/core/cli/data/rule-packs/general-security.json +173 -0
  27. package/core/cli/data/rule-packs/owasp-mcp-2026.json +244 -0
  28. package/core/cli/data/rule-packs/toxic-flow-heuristics.json +21 -0
  29. package/core/cli/data/rule-sources.json +5 -0
  30. package/core/cli/data/secret-patterns.json +18 -0
  31. package/core/cli/data/tool-classifications.json +111 -0
  32. package/core/cli/data/toxic-flow-rules.json +47 -0
  33. package/core/cli/index.js +23 -0
  34. package/core/cli/output/Banner.js +52 -0
  35. package/core/cli/output/Formatter.js +183 -0
  36. package/core/cli/output/JsonFormatter.js +106 -0
  37. package/core/cli/output/index.js +16 -0
  38. package/core/cli/secureRegistryFetch.js +157 -0
  39. package/core/cli/symbols.js +16 -0
  40. package/core/container/DependencyContainer.js +4 -1
  41. package/core/repositories/PacketRepository.js +16 -0
  42. package/core/services/AuditService.js +2 -0
  43. package/core/services/security/StaticRulesService.js +69 -13
  44. package/core/services/security/TrafficAnalysisService.js +19 -1
  45. package/core/services/security/TrafficToxicFlowService.js +154 -0
  46. package/core/services/security/index.js +2 -1
  47. package/core/services/security/rules/index.js +25 -59
  48. package/core/services/security/rules/scans/configPermissions.js +91 -0
  49. package/core/services/security/rules/scans/duplicateToolNames.js +85 -0
  50. package/core/services/security/rules/scans/insecureTransport.js +148 -0
  51. package/core/services/security/rules/scans/missingContainment.js +123 -0
  52. package/core/services/security/rules/scans/shellEnvInjection.js +101 -0
  53. package/core/services/security/rules/scans/unsafeDefaults.js +99 -0
  54. package/core/services/security/toolsListFromTrafficParser.js +70 -0
  55. package/core/tui/App.js +144 -0
  56. package/core/tui/FindingsPanel.js +115 -0
  57. package/core/tui/FixPanel.js +132 -0
  58. package/core/tui/Header.js +51 -0
  59. package/core/tui/HelpBar.js +42 -0
  60. package/core/tui/ServersPanel.js +109 -0
  61. package/core/tui/ToxicFlowsPanel.js +100 -0
  62. package/core/tui/h.js +8 -0
  63. package/core/tui/index.js +11 -0
  64. package/core/tui/render.js +22 -0
  65. package/package.json +24 -16
  66. package/ui/dist/assets/{index-CiCSDYf-.js → index-Buah4fNS.js} +32 -32
  67. package/ui/dist/index.html +1 -1
  68. package/ui/server/controllers/RequestController.js +9 -1
  69. package/ui/server/controllers/SecurityFindingsController.js +46 -1
  70. package/ui/server/routes/requests.js +8 -1
  71. package/ui/server/routes/security.js +5 -1
  72. package/ui/server/setup.js +2 -0
  73. package/ui/server/swagger/paths/components.js +55 -0
  74. package/ui/server/swagger/paths/securityTrafficFlows.js +59 -0
  75. package/ui/server/swagger/paths.js +2 -0
  76. package/ui/server/swagger/swagger.js +5 -1
  77. package/ui/src/Security.jsx +10 -0
  78. package/ui/src/components/Security/ScannerContent.jsx +30 -1
  79. package/ui/src/components/Security/TrafficToxicFlowsPanel.jsx +253 -0
  80. package/ui/src/components/Security/securityApi.js +15 -0
  81. package/ui/src/components/Security/useSecurity.js +60 -3
  82. package/core/services/security/rules/scans/agentic01GoalHijack.js +0 -130
  83. package/core/services/security/rules/scans/agentic02ToolMisuse.js +0 -129
  84. package/core/services/security/rules/scans/agentic03IdentityAbuse.js +0 -130
  85. package/core/services/security/rules/scans/agentic04SupplyChain.js +0 -130
  86. package/core/services/security/rules/scans/agentic06MemoryPoisoning.js +0 -130
  87. package/core/services/security/rules/scans/agentic07InsecureCommunication.js +0 -135
  88. package/core/services/security/rules/scans/agentic08CascadingFailures.js +0 -135
  89. package/core/services/security/rules/scans/agentic09TrustExploitation.js +0 -135
  90. package/core/services/security/rules/scans/agentic10RogueAgent.js +0 -130
  91. package/core/services/security/rules/scans/hardcodedSecrets.js +0 -130
  92. package/core/services/security/rules/scans/mcp01TokenMismanagement.js +0 -127
  93. package/core/services/security/rules/scans/mcp02ScopeCreep.js +0 -130
  94. package/core/services/security/rules/scans/mcp03ToolPoisoning.js +0 -132
  95. package/core/services/security/rules/scans/mcp04SupplyChain.js +0 -131
  96. package/core/services/security/rules/scans/mcp06PromptInjection.js +0 -200
  97. package/core/services/security/rules/scans/mcp07InsufficientAuth.js +0 -130
  98. package/core/services/security/rules/scans/mcp08LackAudit.js +0 -129
  99. package/core/services/security/rules/scans/mcp09ShadowServers.js +0 -129
  100. package/core/services/security/rules/scans/mcp10ContextInjection.js +0 -130
@@ -5,8 +5,10 @@ import {
5
5
  fetchRunningServersCount,
6
6
  fetchScanHistory,
7
7
  fetchSummary,
8
+ fetchTrafficToxicFlows,
8
9
  postAnalyseRunningServers,
9
10
  postClearFindings,
11
+ postReplayTrafficToxicFlows,
10
12
  } from './securityApi.js';
11
13
  import { useYaraRules } from './useYaraRules.js';
12
14
 
@@ -30,6 +32,11 @@ export function useSecurity() {
30
32
  // Track whether a scan has been completed (to show appropriate empty state)
31
33
  const [scanComplete, setScanComplete] = useState(false);
32
34
 
35
+ // Traffic-derived toxic flows (tools/list via HTTP proxy)
36
+ const [trafficToxicSnapshot, setTrafficToxicSnapshot] = useState(null);
37
+ const [trafficToxicLoading, setTrafficToxicLoading] = useState(false);
38
+ const [trafficToxicError, setTrafficToxicError] = useState(null);
39
+
33
40
  // Use YARA rules hook
34
41
  const yaraRules = useYaraRules();
35
42
 
@@ -88,6 +95,48 @@ export function useSecurity() {
88
95
  }
89
96
  }, []);
90
97
 
98
+ const loadTrafficToxicFlows = useCallback(async () => {
99
+ setTrafficToxicLoading(true);
100
+ setTrafficToxicError(null);
101
+ try {
102
+ const data = await fetchTrafficToxicFlows();
103
+ if (data && data.success === false) {
104
+ setTrafficToxicError(data.error || 'Could not load traffic toxic flows');
105
+ setTrafficToxicSnapshot(null);
106
+ } else if (data?.error && !data.toxicFlows) {
107
+ setTrafficToxicError(data.error);
108
+ setTrafficToxicSnapshot(null);
109
+ } else {
110
+ setTrafficToxicSnapshot(data);
111
+ }
112
+ } catch (err) {
113
+ console.error('Traffic toxic flows:', err);
114
+ setTrafficToxicError(err.message || 'Request failed');
115
+ setTrafficToxicSnapshot(null);
116
+ } finally {
117
+ setTrafficToxicLoading(false);
118
+ }
119
+ }, []);
120
+
121
+ const replayTrafficToxicFlows = useCallback(async () => {
122
+ setTrafficToxicLoading(true);
123
+ setTrafficToxicError(null);
124
+ try {
125
+ const data = await postReplayTrafficToxicFlows();
126
+ if (data.success === false || data.error) {
127
+ setTrafficToxicError(data.error || 'Replay failed');
128
+ setTrafficToxicSnapshot(null);
129
+ } else {
130
+ setTrafficToxicSnapshot(data);
131
+ }
132
+ } catch (err) {
133
+ console.error('Traffic toxic replay:', err);
134
+ setTrafficToxicError(err.message || 'Request failed');
135
+ } finally {
136
+ setTrafficToxicLoading(false);
137
+ }
138
+ }, []);
139
+
91
140
  const discoverAndScan = useCallback(async () => {
92
141
  setScanning(true);
93
142
  setError(null);
@@ -109,6 +158,7 @@ export function useSecurity() {
109
158
  await loadSummary();
110
159
  await loadScanHistory(); // Refresh history
111
160
  setScanComplete(true); // Mark scan as complete
161
+ await loadTrafficToxicFlows();
112
162
  }
113
163
  } catch (err) {
114
164
  console.error('Analysis error:', err);
@@ -116,7 +166,7 @@ export function useSecurity() {
116
166
  } finally {
117
167
  setScanning(false);
118
168
  }
119
- }, [loadFindings, loadSummary, loadScanHistory]);
169
+ }, [loadFindings, loadSummary, loadScanHistory, loadTrafficToxicFlows]);
120
170
 
121
171
  const clearFindings = useCallback(async () => {
122
172
  setClearing(true);
@@ -130,13 +180,14 @@ export function useSecurity() {
130
180
  setError(null);
131
181
  setScanComplete(false); // Reset scan complete state
132
182
  await loadScanHistory(); // Refresh history after clear
183
+ await loadTrafficToxicFlows(); // Server cleared in-memory toxic-flow registry
133
184
  }
134
185
  } catch (err) {
135
186
  console.error('Failed to clear findings:', err);
136
187
  } finally {
137
188
  setClearing(false);
138
189
  }
139
- }, [loadScanHistory]);
190
+ }, [loadScanHistory, loadTrafficToxicFlows]);
140
191
 
141
192
  const selectHistoricalScan = useCallback(async (scanId) => {
142
193
  setSelectedScanId(scanId);
@@ -160,7 +211,8 @@ export function useSecurity() {
160
211
  loadRules();
161
212
  loadScanHistory();
162
213
  checkRunningServers();
163
- }, [loadRules, loadScanHistory, checkRunningServers]);
214
+ loadTrafficToxicFlows();
215
+ }, [loadRules, loadScanHistory, checkRunningServers, loadTrafficToxicFlows]);
164
216
 
165
217
  return {
166
218
  rules,
@@ -183,6 +235,11 @@ export function useSecurity() {
183
235
  runningServersCount,
184
236
  checkRunningServers,
185
237
  scanComplete,
238
+ trafficToxicSnapshot,
239
+ trafficToxicLoading,
240
+ trafficToxicError,
241
+ loadTrafficToxicFlows,
242
+ replayTrafficToxicFlows,
186
243
  // YARA rules (spread from useYaraRules)
187
244
  ...yaraRules,
188
245
  };
@@ -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 = 'asi01-goal-hijack';
5
- const OWASP_ID = 'ASI01';
6
- const RECOMMENDATION =
7
- 'Implement goal validation and verification. Monitor for unauthorized goal changes. Use goal isolation and protection mechanisms.';
8
-
9
- const GOAL_HIJACK_PATTERNS = [
10
- /(?:hijack|override|replace|change|modify)\s+(?:goal|objective|purpose|mission|task)/i,
11
- /(?:ignore|forget|disregard)\s+(?:original|initial|intended|primary)\s+(?:goal|objective|purpose)/i,
12
- /(?:new|different|alternative|malicious)\s+(?:goal|objective|purpose|mission)/i,
13
- /(?:steer|redirect|manipulate)\s+(?:agent|system)\s+(?:toward|to|into)/i,
14
- /(?:unauthorized|malicious|harmful)\s+(?:goal|objective|purpose|action)/i,
15
- ];
16
-
17
- function scanText(text) {
18
- if (!text) {
19
- return null;
20
- }
21
- const matches = [];
22
- for (const pattern of GOAL_HIJACK_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 agent goal hijack in ${entity}: ${matches.join(', ')}`;
33
- }
34
-
35
- export function scanAgentic01GoalHijack(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: 'Goal Hijack',
49
- name: tool?.name || 'tool',
50
- severity: 'high',
51
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
52
- tags: ['goal-hijack', 'agent-manipulation'],
53
- agenticCategory: OWASP_ID,
54
- safeUseNotes:
55
- 'Review tool behavior for goal hijacking vulnerabilities. Ensure agent goals cannot be modified by tools.',
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: 'Goal Hijack',
65
- uri: resource?.uri || resource?.name || 'resource',
66
- severity: 'high',
67
- reasons: [
68
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
69
- ],
70
- tags: ['goal-hijack', 'agent-manipulation'],
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: 'Goal Hijack',
81
- name: prompt?.name || 'prompt',
82
- severity: 'critical',
83
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
84
- tags: ['goal-hijack', 'agent-manipulation'],
85
- agenticCategory: OWASP_ID,
86
- });
87
- }
88
- }
89
-
90
- return results;
91
- }
92
-
93
- const adapter = createRuleAdapter(scanAgentic01GoalHijack, 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: 'Goal Hijack',
109
- severity: 'high',
110
- title: 'Goal Hijack Pattern in Traffic',
111
- description: `Potential agent goal hijack 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: 'Agent Goal Hijack Detection',
125
- owasp_id: OWASP_ID,
126
- severity: 'high',
127
- description: 'Detects attempts to hijack or modify agent goals.',
128
- source: 'static',
129
- type: 'agentic-security',
130
- };
@@ -1,129 +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 = 'asi02-tool-misuse';
5
- const OWASP_ID = 'ASI02';
6
- const RECOMMENDATION =
7
- 'Implement tool usage monitoring and restrictions. Enforce scope boundaries for tool usage. Monitor for unauthorized tool combinations.';
8
-
9
- const TOOL_MISUSE_PATTERNS = [
10
- /(?:misuse|abuse|exploit|manipulate)\s+(?:tool|function|capability|feature)/i,
11
- /(?:use|utilize|invoke)\s+(?:tool|function)\s+(?:outside|beyond|outside\s+of)\s+(?:intended|authorized|allowed)\s+(?:scope|purpose|context)/i,
12
- /(?:unauthorized|illegitimate|improper)\s+(?:tool|function)\s+(?:usage|use|invocation)/i,
13
- /(?:combine|chain|sequence)\s+(?:tools|functions)\s+(?:to|for)\s+(?:achieve|perform|execute)\s+(?:unauthorized|malicious)/i,
14
- ];
15
-
16
- function scanText(text) {
17
- if (!text) {
18
- return null;
19
- }
20
- const matches = [];
21
- for (const pattern of TOOL_MISUSE_PATTERNS) {
22
- const match = text.match(pattern);
23
- if (match) {
24
- matches.push(match[0]);
25
- }
26
- }
27
- return matches.length > 0 ? matches : null;
28
- }
29
-
30
- function buildReason(entity, matches) {
31
- return `Potential tool misuse/exploitation in ${entity}: ${matches.join(', ')}`;
32
- }
33
-
34
- export function scanAgentic02ToolMisuse(mcpData = {}) {
35
- const results = {
36
- toolFindings: [],
37
- resourceFindings: [],
38
- promptFindings: [],
39
- notablePatterns: [],
40
- recommendations: [RECOMMENDATION],
41
- };
42
-
43
- for (const tool of mcpData.tools || []) {
44
- const matches = scanText(toolToText(tool));
45
- if (matches) {
46
- results.toolFindings.push({
47
- issueType: 'Tool Misuse',
48
- name: tool?.name || 'tool',
49
- severity: 'high',
50
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
51
- tags: ['tool-misuse', 'exploitation'],
52
- agenticCategory: OWASP_ID,
53
- safeUseNotes:
54
- 'Review tool usage patterns. Ensure tools are used only within their intended scope.',
55
- });
56
- }
57
- }
58
-
59
- for (const resource of mcpData.resources || []) {
60
- const matches = scanText(resourceToText(resource));
61
- if (matches) {
62
- results.resourceFindings.push({
63
- issueType: 'Tool Misuse',
64
- uri: resource?.uri || resource?.name || 'resource',
65
- severity: 'medium',
66
- reasons: [
67
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
68
- ],
69
- tags: ['tool-misuse', 'exploitation'],
70
- agenticCategory: OWASP_ID,
71
- });
72
- }
73
- }
74
-
75
- for (const prompt of mcpData.prompts || []) {
76
- const matches = scanText(promptToText(prompt));
77
- if (matches) {
78
- results.promptFindings.push({
79
- issueType: 'Tool Misuse',
80
- name: prompt?.name || 'prompt',
81
- severity: 'high',
82
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
83
- tags: ['tool-misuse', 'exploitation'],
84
- agenticCategory: OWASP_ID,
85
- });
86
- }
87
- }
88
-
89
- return results;
90
- }
91
-
92
- const adapter = createRuleAdapter(scanAgentic02ToolMisuse, RULE_ID, OWASP_ID, RECOMMENDATION);
93
-
94
- export const analyzeTool = adapter.analyzeTool;
95
- export const analyzePrompt = adapter.analyzePrompt;
96
- export const analyzeResource = adapter.analyzeResource;
97
-
98
- export function analyzePacket(packet) {
99
- const text = packetToText(packet);
100
- const matches = scanText(text);
101
- if (!matches) {
102
- return [];
103
- }
104
- return [
105
- convertPacketFinding(
106
- {
107
- issueType: 'Tool Misuse',
108
- severity: 'high',
109
- title: 'Tool Misuse Pattern in Traffic',
110
- description: `Potential tool misuse in packet: ${matches.join(', ')}`,
111
- evidence: matches[0]?.substring(0, 50) || '',
112
- },
113
- RULE_ID,
114
- OWASP_ID,
115
- RECOMMENDATION,
116
- packet
117
- ),
118
- ];
119
- }
120
-
121
- export const ruleMetadata = {
122
- id: RULE_ID,
123
- name: 'Tool Misuse Detection',
124
- owasp_id: OWASP_ID,
125
- severity: 'high',
126
- description: 'Detects tool misuse and exploitation patterns.',
127
- source: 'static',
128
- type: 'agentic-security',
129
- };
@@ -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 = 'asi03-identity-abuse';
5
- const OWASP_ID = 'ASI03';
6
- const RECOMMENDATION =
7
- 'Implement strict identity and privilege management. Monitor for privilege escalation. Enforce least privilege principles.';
8
-
9
- const IDENTITY_ABUSE_PATTERNS = [
10
- /(?:abuse|misuse|exploit|impersonate|spoof)\s+(?:identity|privilege|permission|access|role)/i,
11
- /(?:escalate|elevate|raise|upgrade)\s+(?:privilege|permission|access|authority)/i,
12
- /(?:assume|take|steal|hijack)\s+(?:identity|role|privilege|permission)/i,
13
- /(?:unauthorized|illegitimate|improper)\s+(?:privilege|permission|access|authority)\s+(?:use|usage|exercise)/i,
14
- /(?:bypass|circumvent|override)\s+(?:identity|authentication|authorization|access\s+control)/i,
15
- ];
16
-
17
- function scanText(text) {
18
- if (!text) {
19
- return null;
20
- }
21
- const matches = [];
22
- for (const pattern of IDENTITY_ABUSE_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 identity/privilege abuse in ${entity}: ${matches.join(', ')}`;
33
- }
34
-
35
- export function scanAgentic03IdentityAbuse(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: 'Identity Abuse',
49
- name: tool?.name || 'tool',
50
- severity: 'high',
51
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
52
- tags: ['identity-abuse', 'privilege-abuse'],
53
- agenticCategory: OWASP_ID,
54
- safeUseNotes:
55
- 'Review tool privilege requirements. Ensure agents cannot abuse their assigned identities or privileges.',
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: 'Identity Abuse',
65
- uri: resource?.uri || resource?.name || 'resource',
66
- severity: 'high',
67
- reasons: [
68
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
69
- ],
70
- tags: ['identity-abuse', 'privilege-abuse'],
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: 'Identity Abuse',
81
- name: prompt?.name || 'prompt',
82
- severity: 'medium',
83
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
84
- tags: ['identity-abuse', 'privilege-abuse'],
85
- agenticCategory: OWASP_ID,
86
- });
87
- }
88
- }
89
-
90
- return results;
91
- }
92
-
93
- const adapter = createRuleAdapter(scanAgentic03IdentityAbuse, 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: 'Identity Abuse',
109
- severity: 'high',
110
- title: 'Identity Abuse Pattern in Traffic',
111
- description: `Potential identity/privilege abuse 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: 'Identity Abuse Detection',
125
- owasp_id: OWASP_ID,
126
- severity: 'high',
127
- description: 'Detects identity and privilege abuse patterns.',
128
- source: 'static',
129
- type: 'agentic-security',
130
- };
@@ -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 = 'asi04-supply-chain';
5
- const OWASP_ID = 'ASI04';
6
- const RECOMMENDATION =
7
- 'Verify agent framework and model integrity. Use signed and verified dependencies. Monitor for supply chain attacks.';
8
-
9
- const AGENTIC_SUPPLY_CHAIN_PATTERNS = [
10
- /(?:compromised|vulnerable|malicious)\s+(?:agent|framework|model|dependency|package)/i,
11
- /(?:supply\s+chain|dependency)\s+(?:attack|vulnerability|compromise|tampering)/i,
12
- /(?:unsigned|unverified|untrusted)\s+(?:agent|framework|model|dependency)/i,
13
- /(?:tampered|modified|altered)\s+(?:agent|framework|model|dependency)/i,
14
- /(?:typosquatting|brandjacking|namespace)\s+(?:agent|framework|model|package)/i,
15
- ];
16
-
17
- function scanText(text) {
18
- if (!text) {
19
- return null;
20
- }
21
- const matches = [];
22
- for (const pattern of AGENTIC_SUPPLY_CHAIN_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 agentic supply chain vulnerability in ${entity}: ${matches.join(', ')}`;
33
- }
34
-
35
- export function scanAgentic04SupplyChain(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: 'Supply Chain Agentic',
49
- name: tool?.name || 'tool',
50
- severity: 'high',
51
- reasons: [buildReason(`tool "${tool?.name || 'unknown'}"`, matches)],
52
- tags: ['supply-chain', 'agentic'],
53
- agenticCategory: OWASP_ID,
54
- safeUseNotes:
55
- 'Verify agent framework and dependencies. Use trusted sources and verify integrity.',
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: 'Supply Chain Agentic',
65
- uri: resource?.uri || resource?.name || 'resource',
66
- severity: 'high',
67
- reasons: [
68
- buildReason(`resource "${resource?.name || resource?.uri || 'unknown'}"`, matches),
69
- ],
70
- tags: ['supply-chain', 'agentic'],
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: 'Supply Chain Agentic',
81
- name: prompt?.name || 'prompt',
82
- severity: 'medium',
83
- reasons: [buildReason(`prompt "${prompt?.name || 'unknown'}"`, matches)],
84
- tags: ['supply-chain', 'agentic'],
85
- agenticCategory: OWASP_ID,
86
- });
87
- }
88
- }
89
-
90
- return results;
91
- }
92
-
93
- const adapter = createRuleAdapter(scanAgentic04SupplyChain, 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: 'Supply Chain Agentic',
109
- severity: 'high',
110
- title: 'Agentic Supply Chain Pattern in Traffic',
111
- description: `Potential agentic supply chain vulnerability 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: 'Agentic Supply Chain Detection',
125
- owasp_id: OWASP_ID,
126
- severity: 'high',
127
- description: 'Detects agentic supply chain vulnerabilities.',
128
- source: 'static',
129
- type: 'agentic-security',
130
- };