T09 · Insecure Skill Coding Practices
- Location
scripts/mcp_client.py:1657- Finding
Paid MCP operations are not protected by code-enforced transaction confirmation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/mcp_client.py:1657–1674
Vulnerability Type: Missing authorization enforcement for paid operations
Risk Level: Mediumpython else: maybe_auto_update() state_dir = Path.home() / ".beatra" if args.command == "verify": _with_waiting_approval(verify, state_dir=state_dir) elif args.command == "upload": result = _with_waiting_approval( lambda: upload(args.path, mime_type=args.mime_type), state_dir=state_dir, ) print(json.dumps(result, ensure_ascii=False, separators=(",", ":"))) elif args.command in {"tools", "call"}: # Read once: a call retried after collecting an approval reuses them. arguments = _read_tool_arguments() if args.command == "call" else None result = _with_waiting_approval( lambda: _run_command(args.command, getattr(args, "tool_name", None), arguments), state_dir=state_dir, )The unrestricted tool-name input is created at
scripts/mcp_client.py:1575–1589:python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name")Technical Analysis
The Skill documentation requires a separate six-field confirmation card and explicit user approval before each paid voice-cloning, speech-synthesis, or video-generation stage. However, the bundled executable client does not enforce that transaction-level approval.
The
callcommand accepts an arbitrary MCP tool name and reads its arguments from standard input. The resulting tool name and arguments are passed to_run_command, which submits them through the authenticated MCP session. There is no paid-tool allowlist, confirmation token, dry-run gate, price binding, or verification that the user approved the exact operation and arguments.This is security-relevant because the authorization scope in
scripts/authorize.py:38–40includes credit-spend ...[truncated 1946 chars]- Remediation
View remediation
Remediation Suggestions
- Require a short-lived, server-issued confirmation token for every paid operation.
- Bind that token cryptographically or server-side to the exact tool name, normalized arguments, current price, quantity, account, and opaque request ID.
- Reject paid calls when the token is missing, expired, already used, or does not match the submitted operation.
- Maintain an explicit local allowlist separating read-only, upload, and paid tools; fail closed for unknown tool names.
- Add a machine-enforced confirmation field rather than relying exclusively on prose instructions to the Agent.
- Preserve idempotency protections so retrying a confirmed request cannot create a second charge.
- Add tests proving that direct helper invocation cannot submit clone, speech, video, image, or music generation without valid transaction-specific approval.
