T05 · Unauthorized Access and Privilege Escalation
- Location
scripts/mcp-client.js:113- Finding
Authenticated Invocation of Undeclared MCP Tools
- Content
View full analysis
Vulnerability Details
File Location:
scripts/mcp-client.js, lines 113–124 and 141–145
Vulnerability Type: Missing client-side allowlist enforcement
Risk Level: MediumVulnerable Code
js function parseCli(argv) { if (argv.length === 1 && argv[0] === 'list') return { command: 'list' }; if (argv[0] !== 'call' || !TOOL_NAME_PATTERN.test(argv[1] || '')) { throw Object.assign(new Error('用法:list | call <toolName> [--args <jsonObject>]'), { code: 'MCP_INVALID_ARGUMENTS' }); } if (argv.length === 2) return { command: 'call', tool: argv[1], args: {} }; if (argv.length === 4 && argv[2] === '--args') { const args = JSON.parse(argv[3]); if (!args || typeof args !== 'object' || Array.isArray(args)) throw new Error('--args 必须是 JSON 对象。'); return { command: 'call', tool: argv[1], args }; } throw Object.assign(new Error('参数无效。'), { code: 'MCP_INVALID_ARGUMENTS' }); }js const value = await rpc('tools/call', { name: parsed.tool, arguments: parsed.args }, { endpoint, token }); return result(true, 'MCP_TOOL_RESULT', '小安 MCP 工具调用完成。', { tool: parsed.tool, result: parseToolText(value), structuredContent: value?.structuredContent ?? null,Technical Analysis
The Skill manifest declares only three authorized business tools:
list_services,create_booking, andget_booking. However, the command-line client validates tool names solely against the genericTOOL_NAME_PATTERNand forwards any matching name to the remote MCP server.The client then automatically reads the privileged bearer credential from
XIAOAN_MCP_AUTH_TOKENor~/.xiaoan/mcp-auth.json. Consequently, anyone able to invoke the script can use that credential with any MCP tool exposed to it, rather than being constrained to the Skill’s declared booking functions.Although server-side authorization may reduce the practical impact, relying exclusively on the remote server does not enforce least privilege within the bundled Skill. The expos ...[truncated 2057 chars]
- Remediation
View remediation
Remediation Suggestions
-
Introduce an immutable client-side allowlist:
js const ALLOWED_TOOLS = new Set([ 'list_services', 'create_booking', 'get_booking', ]); -
Reject all undeclared names before loading or using the authorization token:
js if (!ALLOWED_TOOLS.has(argv[1])) { throw Object.assign( new Error('Tool is not permitted by this Skill.'), { code: 'MCP_TOOL_NOT_ALLOWED' } ); } -
Add local schemas for each allowed tool and reject unknown fields, invalid types, excessive lengths, or malformed dates and identifiers before network transmission.
-
Configure the remote MCP credential with server-side authorization limited to the same three tools. Client-side restrictions should supplement, not replace, server-side access control.
-
Use separate credentials for user-facing booking operations and any administrative MCP operations.
-
Add automated tests verifying that arbitrary valid-looking names, including newly exposed server tools, are rejected without making a network request or reading the credential.
-
Keep
skill.json, the client allowlist, and the server authorization policy synchronized through release-time validation.
-
