@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.
- package/README.md +482 -56
- package/bin/mcp-shark.js +146 -52
- package/core/cli/AutoFixEngine.js +93 -0
- package/core/cli/ConfigScanner.js +193 -0
- package/core/cli/DataLoader.js +200 -0
- package/core/cli/DeclarativeRuleEngine.js +363 -0
- package/core/cli/DoctorCommand.js +218 -0
- package/core/cli/FixHandlers.js +222 -0
- package/core/cli/HtmlReportGenerator.js +203 -0
- package/core/cli/IdeConfigPaths.js +175 -0
- package/core/cli/ListCommand.js +255 -0
- package/core/cli/LockCommand.js +164 -0
- package/core/cli/LockDiffEngine.js +152 -0
- package/core/cli/RuleRegistryConfig.js +131 -0
- package/core/cli/ScanCommand.js +244 -0
- package/core/cli/ScanService.js +200 -0
- package/core/cli/SecretDetector.js +92 -0
- package/core/cli/SharkScoreCalculator.js +109 -0
- package/core/cli/ToolClassifications.js +51 -0
- package/core/cli/ToxicFlowAnalyzer.js +212 -0
- package/core/cli/UpdateCommand.js +188 -0
- package/core/cli/WalkthroughGenerator.js +195 -0
- package/core/cli/WatchCommand.js +129 -0
- package/core/cli/YamlRuleEngine.js +197 -0
- package/core/cli/data/rule-packs/aauth-visibility.json +117 -0
- package/core/cli/data/rule-packs/agentic-security-2026.json +180 -0
- package/core/cli/data/rule-packs/general-security.json +173 -0
- package/core/cli/data/rule-packs/owasp-mcp-2026.json +244 -0
- package/core/cli/data/rule-packs/toxic-flow-heuristics.json +21 -0
- package/core/cli/data/rule-sources.json +5 -0
- package/core/cli/data/secret-patterns.json +18 -0
- package/core/cli/data/tool-classifications.json +111 -0
- package/core/cli/data/toxic-flow-rules.json +47 -0
- package/core/cli/index.js +23 -0
- package/core/cli/output/Banner.js +52 -0
- package/core/cli/output/Formatter.js +183 -0
- package/core/cli/output/JsonFormatter.js +106 -0
- package/core/cli/output/index.js +16 -0
- package/core/cli/secureRegistryFetch.js +157 -0
- package/core/cli/symbols.js +16 -0
- package/core/configs/environment.js +3 -1
- package/core/configs/index.js +3 -64
- package/core/container/DependencyContainer.js +4 -1
- package/core/mcp-server/index.js +4 -1
- package/core/mcp-server/server/external/all.js +10 -3
- package/core/mcp-server/server/external/config.js +62 -5
- package/core/models/RequestFilters.js +3 -0
- package/core/repositories/PacketRepository.js +16 -0
- package/core/services/AuditService.js +2 -0
- package/core/services/ConfigService.js +9 -1
- package/core/services/ConfigTransformService.js +34 -2
- package/core/services/RequestService.js +58 -5
- package/core/services/ServerManagementService.js +59 -4
- package/core/services/security/StaticRulesService.js +69 -13
- package/core/services/security/TrafficAnalysisService.js +19 -1
- package/core/services/security/TrafficToxicFlowService.js +154 -0
- package/core/services/security/aauthGraph.js +199 -0
- package/core/services/security/aauthParser.js +274 -0
- package/core/services/security/aauthSelfTest.js +346 -0
- package/core/services/security/index.js +2 -1
- package/core/services/security/rules/index.js +25 -59
- package/core/services/security/rules/scans/configPermissions.js +91 -0
- package/core/services/security/rules/scans/duplicateToolNames.js +85 -0
- package/core/services/security/rules/scans/insecureTransport.js +148 -0
- package/core/services/security/rules/scans/missingContainment.js +123 -0
- package/core/services/security/rules/scans/shellEnvInjection.js +101 -0
- package/core/services/security/rules/scans/unsafeDefaults.js +99 -0
- package/core/services/security/toolsListFromTrafficParser.js +70 -0
- package/core/tui/App.js +144 -0
- package/core/tui/FindingsPanel.js +115 -0
- package/core/tui/FixPanel.js +132 -0
- package/core/tui/Header.js +51 -0
- package/core/tui/HelpBar.js +42 -0
- package/core/tui/ServersPanel.js +109 -0
- package/core/tui/ToxicFlowsPanel.js +100 -0
- package/core/tui/h.js +8 -0
- package/core/tui/index.js +11 -0
- package/core/tui/render.js +22 -0
- package/package.json +24 -16
- package/ui/dist/assets/index-D6zDrtMV.js +81 -0
- package/ui/dist/index.html +1 -1
- package/ui/server/controllers/AauthController.js +279 -0
- package/ui/server/controllers/RequestController.js +12 -1
- package/ui/server/controllers/SecurityFindingsController.js +46 -1
- package/ui/server/routes/aauth.js +18 -0
- package/ui/server/routes/requests.js +8 -1
- package/ui/server/routes/security.js +5 -1
- package/ui/server/setup.js +224 -6
- package/ui/server/swagger/paths/components.js +55 -0
- package/ui/server/swagger/paths/securityTrafficFlows.js +59 -0
- package/ui/server/swagger/paths.js +2 -2
- package/ui/server/swagger/swagger.js +5 -2
- package/ui/server.js +1 -1
- package/ui/src/App.jsx +26 -52
- package/ui/src/PacketFilters.jsx +31 -1
- package/ui/src/PacketList.jsx +2 -2
- package/ui/src/Security.jsx +10 -0
- package/ui/src/TabNavigation.jsx +8 -0
- package/ui/src/components/AAuthBadge.jsx +92 -0
- package/ui/src/components/AauthExplorer/AauthExplorerGraph.jsx +231 -0
- package/ui/src/components/AauthExplorer/AauthExplorerView.jsx +387 -0
- package/ui/src/components/AauthExplorer/NodeDetailPanel.jsx +272 -0
- package/ui/src/components/App/ActionMenu.jsx +4 -31
- package/ui/src/components/App/ApiDocsButton.jsx +0 -1
- package/ui/src/components/App/ShutdownButton.jsx +0 -1
- package/ui/src/components/App/useAppState.js +19 -26
- package/ui/src/components/DetailsTab/AAuthIdentitySection.jsx +119 -0
- package/ui/src/components/DetailsTab/RequestDetailsSection.jsx +2 -0
- package/ui/src/components/DetailsTab/ResponseDetailsSection.jsx +2 -0
- package/ui/src/components/DetectedPathsList.jsx +1 -5
- package/ui/src/components/FileInput.jsx +0 -1
- package/ui/src/components/PacketFilters/AAuthPostureFilter.jsx +81 -0
- package/ui/src/components/RequestRow/RequestRowMain.jsx +7 -1
- package/ui/src/components/Security/AAuthPosturePanel.jsx +360 -0
- package/ui/src/components/Security/ScannerContent.jsx +33 -1
- package/ui/src/components/Security/TrafficToxicFlowsPanel.jsx +253 -0
- package/ui/src/components/Security/securityApi.js +15 -0
- package/ui/src/components/Security/useSecurity.js +60 -3
- package/ui/src/components/ServerControl.jsx +0 -1
- package/ui/src/components/TabNavigation/DesktopTabs.jsx +0 -11
- package/ui/src/components/TabNavigationIcons.jsx +5 -0
- package/ui/src/components/ViewModeTabs.jsx +0 -1
- package/ui/src/utils/animations.js +26 -9
- package/core/services/security/rules/scans/agentic01GoalHijack.js +0 -130
- package/core/services/security/rules/scans/agentic02ToolMisuse.js +0 -129
- package/core/services/security/rules/scans/agentic03IdentityAbuse.js +0 -130
- package/core/services/security/rules/scans/agentic04SupplyChain.js +0 -130
- package/core/services/security/rules/scans/agentic06MemoryPoisoning.js +0 -130
- package/core/services/security/rules/scans/agentic07InsecureCommunication.js +0 -135
- package/core/services/security/rules/scans/agentic08CascadingFailures.js +0 -135
- package/core/services/security/rules/scans/agentic09TrustExploitation.js +0 -135
- package/core/services/security/rules/scans/agentic10RogueAgent.js +0 -130
- package/core/services/security/rules/scans/hardcodedSecrets.js +0 -130
- package/core/services/security/rules/scans/mcp01TokenMismanagement.js +0 -127
- package/core/services/security/rules/scans/mcp02ScopeCreep.js +0 -130
- package/core/services/security/rules/scans/mcp03ToolPoisoning.js +0 -132
- package/core/services/security/rules/scans/mcp04SupplyChain.js +0 -131
- package/core/services/security/rules/scans/mcp06PromptInjection.js +0 -200
- package/core/services/security/rules/scans/mcp07InsufficientAuth.js +0 -130
- package/core/services/security/rules/scans/mcp08LackAudit.js +0 -129
- package/core/services/security/rules/scans/mcp09ShadowServers.js +0 -129
- package/core/services/security/rules/scans/mcp10ContextInjection.js +0 -130
- package/ui/dist/assets/index-CiCSDYf-.js +0 -97
- package/ui/server/routes/help.js +0 -44
- package/ui/server/swagger/paths/help.js +0 -82
- package/ui/src/HelpGuide/HelpGuideContent.jsx +0 -118
- package/ui/src/HelpGuide/HelpGuideFooter.jsx +0 -59
- package/ui/src/HelpGuide/HelpGuideHeader.jsx +0 -57
- package/ui/src/HelpGuide.jsx +0 -78
- package/ui/src/IntroTour.jsx +0 -154
- package/ui/src/components/App/HelpButton.jsx +0 -90
- package/ui/src/components/TourOverlay.jsx +0 -117
- package/ui/src/components/TourTooltip/TourTooltipButtons.jsx +0 -120
- package/ui/src/components/TourTooltip/TourTooltipHeader.jsx +0 -71
- package/ui/src/components/TourTooltip/TourTooltipIcons.jsx +0 -54
- package/ui/src/components/TourTooltip/useTooltipPosition.js +0 -135
- package/ui/src/components/TourTooltip.jsx +0 -91
- package/ui/src/config/tourSteps.jsx +0 -140
|
@@ -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
|
-
|
|
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
|
};
|
|
@@ -28,17 +28,6 @@ export default function DesktopTabs({ tabs, activeTab, onTabChange, tabRefs, ind
|
|
|
28
28
|
tabRefs.current[tab.id] = el;
|
|
29
29
|
}
|
|
30
30
|
}}
|
|
31
|
-
data-tour={
|
|
32
|
-
tab.id === 'traffic'
|
|
33
|
-
? 'traffic-tab'
|
|
34
|
-
: tab.id === 'logs'
|
|
35
|
-
? 'logs-tab'
|
|
36
|
-
: tab.id === 'setup'
|
|
37
|
-
? 'setup-tab'
|
|
38
|
-
: tab.id === 'playground'
|
|
39
|
-
? 'playground-tab'
|
|
40
|
-
: 'smart-scan-tab'
|
|
41
|
-
}
|
|
42
31
|
onClick={() => onTabChange(tab.id)}
|
|
43
32
|
style={{
|
|
44
33
|
padding: '14px 24px',
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
IconBrandStackoverflow,
|
|
5
5
|
IconChevronDown,
|
|
6
6
|
IconFileText,
|
|
7
|
+
IconKey,
|
|
7
8
|
IconMenu2,
|
|
8
9
|
IconNetwork,
|
|
9
10
|
IconSettings,
|
|
@@ -43,3 +44,7 @@ export const ChevronDownIcon = ({ size = 16, color = 'currentColor' }) => (
|
|
|
43
44
|
export const SecurityIcon = ({ size = 16, color = 'currentColor' }) => (
|
|
44
45
|
<IconShieldCheck size={size} stroke={1.5} color={color} />
|
|
45
46
|
);
|
|
47
|
+
|
|
48
|
+
export const AauthIcon = ({ size = 16, color = 'currentColor' }) => (
|
|
49
|
+
<IconKey size={size} stroke={1.5} color={color} />
|
|
50
|
+
);
|
|
@@ -5,18 +5,35 @@ import anime from 'animejs';
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
* Stagger animation for list items
|
|
8
|
+
* Stagger animation for list items.
|
|
9
|
+
* @param {object} [options]
|
|
10
|
+
* @param {boolean} [options.fade=true] When false, rows stay at full opacity so
|
|
11
|
+
* traffic tables are never invisible during the tween (fixes empty screenshots
|
|
12
|
+
* and reduces flash for long lists).
|
|
9
13
|
*/
|
|
10
14
|
export const staggerIn = (selector, options = {}) => {
|
|
11
|
-
|
|
15
|
+
const {
|
|
16
|
+
fade = true,
|
|
17
|
+
duration = 400,
|
|
18
|
+
delay = 50,
|
|
19
|
+
easing = 'easeOutExpo',
|
|
20
|
+
translateY = [20, 0],
|
|
21
|
+
...rest
|
|
22
|
+
} = options;
|
|
23
|
+
const cfg = {
|
|
12
24
|
targets: selector,
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
translateY,
|
|
26
|
+
duration,
|
|
27
|
+
delay: anime.stagger(delay),
|
|
28
|
+
easing,
|
|
29
|
+
...rest,
|
|
30
|
+
};
|
|
31
|
+
if (fade) {
|
|
32
|
+
cfg.opacity = [0, 1];
|
|
33
|
+
} else {
|
|
34
|
+
cfg.opacity = 1;
|
|
35
|
+
}
|
|
36
|
+
return anime(cfg);
|
|
20
37
|
};
|
|
21
38
|
|
|
22
39
|
/**
|
|
@@ -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
|
-
};
|