T05 · Unauthorized Access and Privilege Escalation
- Location
- scripts/authorize.py:30
- Finding
- Overprivileged Device Token Combined with Unrestricted MCP Tool Invocation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:30-34`; additionally exploitable through `scripts/mcp_client.py:1460-1479` and `scripts/mcp_client.py:1497-1499` **Vulnerability Type**: Violation of least privilege and unrestricted access to remotely exposed MCP tools **Risk Level**: High ### Vulnerable Code ```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" ) ``` The generic command handler accepts any tool name supplied on the command line and forwards arbitrary JSON arguments: ```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}, ) ``` ```python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name") ``` ### Technical Analysis The declared purpose of this Skill is to create radio-drama bumper audio, optionally clone an authorized voice, upload a sample, inspect models and voices, monitor tasks, and query billing information. The authorization request nevertheless obtains permissions for unrelated image, video, and music generation, as well as broad artifact, task-cancellation, and wallet-spending capabilities. This violates least privilege ...[truncated 2403 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Request only capabilities required by this Skill: - Speech generation. - Voice listing. - Voice creation only when cloning is explicitly enabled. - Artifact upload/read only when an authorized local sample is used. - Task read and narrowly scoped cancellation. - Read-only wallet access where required. 2. Remove image, video, and music generation scopes from this package. 3. Avoid a general wallet-spending scope where the service can instead authorize only explicit Skill operations. 4. Replace the unrestricted tool dispatcher with a package-specific allowlist, for example: - `beatra.models.list` - `beatra.voices.list` - `beatra.voices.clone` - `beatra.speech.synthesize` - `beatra.assets.upload` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.tasks.cancel` - `beatra.wallet.get` - `beatra.wallet.ledger` - `beatra.installations.register` 5. Reject every tool not present in the allowlist before creating an MCP request. 6. Where supported, issue a separate short-lived grant for optional voice cloning or uploads rather than permanently including those permissions. 7. Bind authorization server-side to the package identity and enforce the same tool allowlist remotely, so bypassing the local client does not restore excessive access. 8. Require explicit user confirmation immediately before operations that spend credits or cancel tasks. ]]>
