T05 · Unauthorized Access and Privilege Escalation
Error
- Location
- scripts/authorize.py:34
- Finding
- Authorization Scope and Local Upload Capability Exceed the Skill's Music-Generation Requirements<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37`; `scripts/mcp_client.py:191-223`; `scripts/mcp_client.py:1438-1446` **Vulnerability Type**: Excessive OAuth permissions and unnecessary local-file upload capability **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 bundled client also implements arbitrary local-file reading for uploads: ```python def _read_local_upload(path: Path) -> tuple[str, bytes]: candidate = path.expanduser() descriptor = -1 try: flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) descriptor = os.open(candidate, flags) before = os.fstat(descriptor) if ( not stat.S_ISREG(before.st_mode) or before.st_size < 1 or before.st_size > MAX_UPLOAD_BYTES ): raise RuntimeError( f"Local upload must be one regular file between 1 and {MAX_UPLOAD_BYTES} bytes" ) with os.fdopen(descriptor, "rb") as handle: descriptor = -1 content = handle.read(MAX_UPLOAD_BYTES + 1) after = os.fstat(handle.fileno()) stable_fields = ("st_dev", "st_ino", "st_size", "st_mtime_ns") if ( len(content) != before.st_size or len(content) > MAX_UPLOAD_BYTES or any(getattr(before, field) != getattr(after, field) for field in stable_fields) ): raise RuntimeError("Local upload changed while it was being read") except RuntimeError: raise except OSError as exc: raise RuntimeError("Local upload must be one readable regular file") from exc finally: if descriptor >= 0: os.close(descriptor) return candidate.name, content ``` The upload command passes the resulting cont ...[truncated 3412 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the shared broad scope with a package-specific, least-privilege authorization grant. 2. Limit the grant to music generation, model or price lookup, necessary task reads, result reads, and narrowly scoped billing operations. 3. Remove these scopes unless a separately declared and user-approved workflow requires them: - `images:generate` - `videos:generate` - `speech:generate` - `voices:read` - `voices:write` - Generic `artifacts:write` - Generic `tasks:cancel` 4. Replace general `wallet:spend` authority with a service-side permission restricted to music generation, if the platform supports capability-specific spending. 5. Remove the local upload command from this package. If upload is retained for another documented workflow: - Require an explicit user confirmation naming the exact file. - Restrict files to a user-selected workspace or allowlisted directory. - Display the destination hostname and file size before transmission. - Reject credential files, SSH material, environment files, and other known-sensitive paths. 6. Add a local allowlist of MCP tool names appropriate to this Skill rather than accepting arbitrary tool names. 7. Use separate credentials per package or per capability so compromise of one Skill cannot exercise unrelated Beatra services. ]]>
