Back to skill

Security audit

Incident Brief Voice Pack

Security checks for vulnerabilities and agentic risk

Overview

This voice-generation skill is mostly coherent, but it grants broad Beatra account authority and silently updates its own installed code, so it should be reviewed carefully before installation.

Install only if you are comfortable giving this package a shared Beatra device token that can cover more than speech generation and with automatic package updates enabled by default. Before using it in a sensitive environment, consider disabling auto-updates with the documented command and confirm that Beatra account permissions, billing exposure, and local credential storage match your risk tolerance.

Vulnerability Patterns
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/authorize.py:34
Finding
Speech-only Skill requests excessive cross-media and account privileges<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37` **Additional Locations**: `references/installation-and-auth.md:73-74`, `references/mcp-connection.md:9-10`, `scripts/mcp_client.py:1475-1483` **Vulnerability Type**: Excessive OAuth scopes and unrestricted remote tool dispatch **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 client also exposes a generic remote tool dispatcher: ```python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name") ``` ```python assert tool_name is not None return session.request( 2, "tools/call", {"name": tool_name, "arguments": arguments}, ) ``` The documentation confirms that this broad authorization is intentional: ```text One approval covers image, video, music, speech, upload, model, and task tools. ``` ### Technical Analysis The declared functionality requires text-to-speech generation, optional voice cloning and sample upload, model and voice discovery, billing access, and task management. It does not require image, video, or music generation. Nevertheless, the authorization flow requires privileges for all these unrelated media types. The resulting bearer credential also includes wallet spending and artifact access. In addition, the bundled client accepts an arbitrary MCP tool name rather than enforcing a package-specific allowlist. This violates the principle of least privilege. Although the credential file is appropriately protected on POSIX systems with owner-only permissions and symlink checks, compromise of the credential or execution context would expose substantially more account authority than this Skill legitimately needs. ### Attack Path 1. The user authorizes the incident voice Skill. 2. Beatra i ...[truncated 1118 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared full-scope authorization with a package-specific, least-privilege credential. 2. Remove unrelated scopes, particularly: - `images:generate` - `videos:generate` - `music:generate` 3. Retain only the permissions required for speech synthesis, optional authorized voice cloning and upload, model or voice discovery, billing, and task management. 4. Add an explicit allowlist in `scripts/mcp_client.py` for the tools this package may invoke. 5. Reject tool names not required by the declared workflow before sending an MCP request. 6. Require a new, explicit authorization decision before adding capabilities to an existing installation. 7. Where possible, separate read-only wallet and task permissions from billable generation permissions. 8. Avoid sharing a single full-scope Device Token among unrelated Skill packages. ]]>

T03 · Remote Payload Retrieval and Execution

Warning
Location
scripts/mcp_client.py:972
Finding
Default silent auto-update creates a post-review remote code execution channel<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:972-1017` **Additional Locations**: `scripts/mcp_client.py:31-32`, `scripts/mcp_client.py:514-521`, `scripts/mcp_client.py:1536-1538`, `SKILL.md:184-197`, `references/automatic-updates-and-safety.md:3-7` **Vulnerability Type**: Automatic retrieval and replacement of executable package code **Risk Level**: Medium ### Vulnerable Code The update state defaults to automatic installation: ```python def _read_update_state(update_home: Path) -> dict[str, Any]: path = update_home / "state.json" try: value = json.loads(path.read_text(encoding="utf-8")) except (OSError, json.JSONDecodeError): return {"schema_version": 1, "auto_update": True} if not isinstance(value, dict) or value.get("schema_version") != 1: return {"schema_version": 1, "auto_update": True} return value ``` The automatic updater downloads and applies remotely published files: ```python def maybe_auto_update( *, state_dir: Path | None = None, install_root: Path | None = None, get_bytes: GetBytes = _default_get_bytes, now: float | None = None, ) -> bool: """Best-effort silent update. Never block the requested MCP command.""" resolved_state = state_dir or Path.home() / ".beatra" try: resolved_root = (install_root or _current_install_root()).resolve() update_home = _update_home(resolved_state, resolved_root) observed_at = time.time() if now is None else now nonce = _lock_update(update_home, now=observed_at) if nonce is None: return False try: recover_update(state_dir=resolved_state, install_root=resolved_root) state = _read_update_state(update_home) if state.get("auto_update", True) is False: return False last_checked = state.get("last_checked_at") if ( isinstance(last_checked, (int, float)) ...[truncated 3861 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. 2. Make the default behavior check-only and notify the user when an update is available. 3. Require explicit user confirmation before downloading or replacing package files. 4. Sign release manifests with an offline publisher key and embed the corresponding public key in the reviewed client. 5. Verify signatures independently of HTTPS and publisher-supplied checksums. 6. Consider recording releases in a verifiable transparency log. 7. Separate update checks from billable or business-tool invocations so ordinary operations do not modify executable code. 8. Pin reviewed package versions in managed and security-sensitive environments. 9. Require additional confirmation before replacing `scripts/mcp_client.py` or other executable files. 10. Preserve the existing path, size, ownership, rollback, redirect, and downgrade protections as defense-in-depth. ]]>
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (3)

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill declares no permissions while instructing use of local file access, shell execution, networked MCP calls, uploads, and package update operations. This undermines least-privilege controls and informed consent because a host or reviewer cannot accurately understand or gate what the skill can do before execution.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The stated purpose is simple voice-clip generation, but the skill also describes authentication flows, credential storage, generic remote tool invocation, local file upload, telemetry/registration, uninstall cleanup, and automatic self-update from remote infrastructure. That gap is security-significant because users may approve a narrowly described content task without realizing the skill can access credentials, execute broader network operations, and modify its own installed package over time.

Self-Modification

High
Category
Rogue Agent
Content
)
    update = subparsers.add_parser(
        "update",
        help="Check, install, or configure Beatra package self-updates",
    )
    update.add_argument(
        "--check",
Confidence
83% confidence
Finding
The client includes a self-update mechanism that downloads and replaces package files on disk. Although it performs several integrity checks, any auto-updating, self-modifying agent component materially increases supply-chain risk: a compromise of the vendor's discovery endpoint, signing/checksum publication process, CDN origin, or trust chain could result in silent execution of attacker-controlled code in future runs. In the context of an agent skill, this is more dangerous because updates can alter behavior after installation without a separate review step.

Static analysis

No suspicious patterns detected.