T09 · Insecure Skill Coding Practices
- Location
scripts/mcp_client.py:2299- Finding
Billable MCP operations can bypass the documented user-confirmation gate
- Content
View full analysis
Vulnerability Details
File Location:
scripts/mcp_client.py:2299-2316, 2383, 2471-2476
Vulnerability Type: Missing authorization enforcement for billable tool calls
Risk Level: MediumRelevant security requirement:
SKILL.md:102-118Complete Code Snippet
python def _run_command( command: str, tool_name: str | None = None, arguments: dict[str, Any] | None = None, ) -> dict[str, Any]: session = _session_with_registration( state_dir=Path.home() / ".beatra", post_json=_default_post_json, ) if command == "tools": return session.request(2, "tools/list", {}) if arguments is None: arguments = _read_tool_arguments() assert tool_name is not None return session.request( 2, "tools/call", {"name": tool_name, "arguments": arguments}, )python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name")python elif args.command in {"tools", "call"}: 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 documented gate states:
text Planning or “make the video” is not approval. Do not create `client_request_id` or submit until the user confirms they have topped up or already have enough credits for this estimate.Technical Analysis
The generic
callcommand accepts an arbitrary MCP tool name from the command line and an arbitrary argument object from standard input._run_commandthen forwards both directly through an authenticated MCP session.The credential scope declared by the authorization helper includes video-generation and
wallet:spendcapabilities. The client does not distinguish read-only tools from billable tools and does not enforce the workflow’s required admissio ...[truncated 2097 chars]- Remediation
View remediation
Remediation Suggestions
- Add a strict tool allowlist and classify each supported tool as read-only, upload, non-billable, or billable.
- Reject billable
tools/callrequests unless they carry a locally verifiable, single-use approval record. - Bind that record to the exact MCP tool name and a canonical hash of all arguments, including the prompt, ordered inputs, model, duration, resolution, aspect ratio, watermark choice, live estimate, and
client_request_id. - Create the approval record only after presenting the admission card and receiving explicit confirmation from the user.
- Expire the record promptly and mark it consumed atomically after one accepted submission.
- Require fresh approval whenever any request field changes.
- Preserve the documented idempotent retry behavior by permitting retries only for byte-equivalent arguments with the same frozen
client_request_id. - Keep read-only account, model-discovery, task-lookup, and planning operations outside the paid-operation gate, while validating them against an explicit allowlist.
- Add tests proving that direct CLI invocation of every billable tool fails without a matching approval record and succeeds only once with a valid record.
