T05 · Unauthorized Access and Privilege Escalation
Warning
- Location
- scripts/authorize.py:29
- Finding
- Overprivileged Device Token Grants Capabilities Unrelated to the Skill<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:29-33` **Vulnerability Type**: Excessive OAuth scope and violation of least privilege **Risk Level**: Medium ### 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 authorization process also collects an Agent-platform identifier and local hostname: ```python def detect_host_platform(explicit: str | None = None) -> str: """The agent environment this process runs inside (docs/device-model.md). Order: explicit agent self-report > environment signatures > unknown. Detection reads the process environment only — nothing else runs, nothing reaches the network. """ if explicit: candidate = explicit.strip().lower().replace(" ", "-") if _PLATFORM_VALUE.fullmatch(candidate): return candidate env = os.environ if env.get("CLAUDECODE") == "1" or "CLAUDE_CODE_ENTRYPOINT" in env: return "claude-code" if any(key.startswith("CODEX_") for key in env): return "codex" ai_agent = env.get("AI_AGENT", "").lower() matched = re.match(r"([a-z0-9-]+)_", ai_agent) if matched and _PLATFORM_VALUE.fullmatch(matched.group(1)): return matched.group(1) return "unknown" def device_display_name() -> str | None: """A hostname the user will recognise in the console device list.""" try: name = socket.gethostname().strip() except OSError: return None if not name or not name.isprintable(): return None return name[:120] ``` These values are included in the device-authorization request: ```python form: dict[str, str] = { "client_id": CLIENT_ID, "resource": MCP_URL, "scope": SCOPE, "platform": host_platform, "client_name": PACKAGE_DISPLAY_NAME, "external_installation_ref": external_r ...[truncated 2873 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove capabilities that are not required by the documented workflow, particularly: - `images:generate` - `music:generate` 2. Issue a package-specific token rather than reusing a broadly scoped credential shared by multiple Skills. 3. Separate read-only, generation, cancellation, and spending permissions so users can authorize only the capabilities they need. 4. Add a local allowlist in `scripts/mcp_client.py` covering only documented Beatra tools. Reject arbitrary tool names before sending a request. 5. Make hostname transmission opt-in and explain it before authorization. 6. Prefer a user-provided device label or random installation identifier over `socket.gethostname()`. 7. Update the privacy and registration documentation to enumerate every transmitted metadata field, its purpose, retention, and disablement mechanism. ]]>
