Back to skill

Security audit

小安智能健身

Security checks for vulnerabilities and agentic risk

Overview

This booking skill is mostly coherent, but its included client can use the merchant token to call any MCP tool on the server, not just the declared booking tools.

Install only if you trust the merchant MCP server and credential scope. Before production use, the publisher should restrict the bundled client and server credential to list_services, create_booking, and get_booking so the token cannot invoke unrelated MCP tools.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T05 · Unauthorized Access and Privilege Escalation

Warning
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: Medium

Vulnerable 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, and get_booking. However, the command-line client validates tool names solely against the generic TOOL_NAME_PATTERN and forwards any matching name to the remote MCP server.

The client then automatically reads the privileged bearer credential from XIAOAN_MCP_AUTH_TOKEN or ~/.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

  1. Introduce an immutable client-side allowlist:

    js
    const ALLOWED_TOOLS = new Set([
      'list_services',
      'create_booking',
      'get_booking',
    ]);
    
  2. 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' }
      );
    }
    
  3. Add local schemas for each allowed tool and reject unknown fields, invalid types, excessive lengths, or malformed dates and identifiers before network transmission.

  4. 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.

  5. Use separate credentials for user-facing booking operations and any administrative MCP operations.

  6. 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.

  7. Keep skill.json, the client allowlist, and the server authorization policy synchronized through release-time validation.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (5)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill invokes a remote MCP service and a bundled Node client that can use network access and read credentials from environment variables or a local auth file, but it does not declare any explicit tool scope such as allowed-tools or permissions. This creates a permission-boundary gap: hosts and reviewers cannot clearly constrain or audit what external/networked capabilities the skill is expected to use, increasing the risk of overbroad access or unintended credential exposure through the client path.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

This file presents operational and error messages in Chinese, and the pattern continues throughout the script, without offering the user any locale selection or documenting that the tool is intentionally Chinese-only. That creates a language policy concern because the skill forces a specific language without user opt-in.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
86% confidence
Finding

L007 规定“所有日期使用 YYYY-MM-DD,时区为 Asia/Shanghai”,属于明确的语言/locale 约束。文档未说明这是仅适用于特定地区用户,或允许根据用户所在地/偏好调整,因此构成未经用户选择的 locale 策略限制。

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
89% confidence
Finding

This code accesses a sensitive credential via process.env.XIAOAN_MCP_AUTH_TOKEN and falls back to ~/.xiaoan/mcp-auth.json, but the file contains no prompt, warning, or user-facing notice that credentials will be read from these locations. Because credential access is safety-relevant and not inherently disclosed by the CLI usage text, this meets the missing-warning criterion for code files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The rpc function performs outbound POST requests and transmits JSON-RPC method parameters, including tool arguments, to the remote MCP server. This file does not include any confirmation prompt or explicit disclosure that user-supplied arguments will be sent over the network, so the behavior lacks a visible warning within the code.

Content

No source excerpt is available for this finding.