T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- scripts/authorize.py:31
- Finding
- Overprivileged Device Token Combined with Unrestricted MCP Tool Dispatch## Vulnerability Details **File Location**: `scripts/authorize.py:31-34`; `scripts/mcp_client.py:1463-1482` **Vulnerability Type**: Excessive authorization scope and unrestricted privileged tool selection **Risk Level**: Medium ### Vulnerable Code `scripts/authorize.py:31-34`: ```python SCOPE = ( "mcp:tools artifacts:write images:generate videos:generate music:generate " "speech:generate voices:read voices:write wallet:spend tasks:read artifacts:read tasks:cancel" ) ``` `scripts/mcp_client.py:1463-1482`: ```python def _run_command(command: str, tool_name: str | 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", {}) try: arguments = json.load(os.sys.stdin) except json.JSONDecodeError as exc: raise RuntimeError("Tool arguments on stdin must be one JSON object") from exc if not isinstance(arguments, dict): raise RuntimeError("Tool arguments on stdin must be one JSON object") assert tool_name is not None return session.request( 2, "tools/call", {"name": tool_name, "arguments": arguments}, ) ``` ### Technical Analysis The declared office-floor-tour workflow needs a comparatively narrow set of capabilities: uploading source images, listing compatible models, generating videos, reading task results, and optionally reading wallet information. The authorization helper instead requests a shared bearer token that also permits unrelated image, music, speech, and voice generation, voice writes, wallet spending, and task cancellation. The generic `call` command accepts an arbitrary `tool_name` from the command line and forwards it to the remote MCP server without enforcing a package-specific allowlist. JSON arguments are likewise accepte ...[truncated 2356 chars]
- Remediation
- ## Remediation Suggestions 1. Replace the broad shared scope with package-specific least-privilege authorization. Retain only permissions required for image upload, model discovery, video generation, necessary task reads, artifact reads, and explicitly documented read-only wallet queries. 2. Remove unrelated permissions such as music generation, speech generation, voice generation and writes, generic image generation, and task cancellation unless a separately documented workflow requires them. 3. Separate read-only wallet access from spending authority. Do not grant `wallet:spend` merely to display balances or ledger entries. 4. Enforce a local allowlist before issuing `tools/call`. For this Skill, allow only the documented operations, such as: - `beatra.assets.upload` - `beatra.models.list` - `beatra.videos.animate` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.wallet.get` - `beatra.wallet.ledger` 5. Reject every unrecognized tool name by default, even if it appears in the server's `tools/list` response. 6. If cancellation or another sensitive operation is later required, expose it through a dedicated command that validates arguments and requires explicit user confirmation. 7. Prefer separate package-bound credentials so another Beatra Skill cannot inherit capabilities that this package does not require. 8. Add automated tests asserting that unrelated, billable, and destructive tool names are rejected locally and that the requested authorization scope contains no permissions outside the documented workflow.
