Back to skill

Security audit

Account Opening Voice Pack

Security checks for vulnerabilities and agentic risk

Overview

The skill mainly performs Beatra voice generation, but it also requests broad account powers and silently updates its own package files, so it belongs in Review before installation.

Review this before installing, especially in regulated or shared environments. Be comfortable with Beatra Device Authorization, a shared token stored under ~/.beatra, paid remote operations, local upload of authorized voice samples, platform/installation registration, and default silent package updates. Disable automatic updates before use if deterministic reviewed code is required.

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 (3)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Default-Enabled Silent Remote Package Replacement<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:31-32, 969-1017, 1543` **Additional Locations**: `SKILL.md:184-201`; `references/automatic-updates-and-safety.md:3-19` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: High ### Vulnerable Code ```python PACKAGE_DISCOVERY_URL = "https://beatra.ai/skills/broker-account-voice/channels/clawhub/install.json" PACKAGE_CDN_BASE_TEMPLATE = "https://cdn.beatra.ai/agent-packages/broker-account-voice/channels/clawhub/v{version}" ``` ```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)) and observed_at - float(last_checked) < UPDATE_CHECK_MAX_AGE_SECONDS ): return False state["last_checked_at"] = observed_at _write_private_json(update_home / "state.json", state) checked = check_update(get_bytes=get_bytes) if not checked["update_available"]: return False _ensure_owned_baseline( install_root= ...[truncated 2958 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic updates by default and require explicit, informed approval before each package replacement. 2. Display the current version, target version, source, and affected files before applying an update. 3. Authenticate release metadata and artifacts using a pinned offline public key, such as Ed25519 signatures, rather than relying only on hashes delivered by the same publication infrastructure. 4. Separate update verification from the executable being replaced, or use a trusted host-managed package updater. 5. Do not permit the updater to replace its own verification component without an independently trusted bootstrap mechanism. 6. Preserve the existing fixed-origin, redirect rejection, archive validation, size limits, ownership checks, transaction journal, and rollback controls. 7. Record auditable update events and provide a supported mechanism to pin a reviewed version. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:34
Finding
Authorization Scope Exceeds the Voice Pack's Functional Requirements<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37`; `scripts/mcp_client.py:1463-1482` **Additional Location**: `references/installation-and-auth.md:73-74` **Vulnerability Type**: Excessive authorization and unrestricted remote tool dispatch **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" ) ``` ```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 Skill's declared function is to synthesize account-opening speech clips and, when explicitly requested, clone a voice from an authorized sample. Legitimate operations include speech generation, voice listing/cloning, artifact upload/read access, task polling/cancellation, and limited billing access. The requested token additionally grants image generation, video generation, music generation, broad wallet spending, and generic MCP tool access. These capabilities are unrelated to the declared voice-pack workflow. The bundled `call` command accepts an arbitrary tool name and does not enforce a local allowlist, so the excessive token scopes are directly reachable through the client. ...[truncated 1372 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared full-scope credential with a package-specific, least-privilege token. 2. Remove `images:generate`, `videos:generate`, and `music:generate` from this Skill's authorization request. 3. Split wallet permissions into narrowly scoped read and task-specific charge capabilities where supported; avoid general wallet spending authority. 4. Add a local allowlist for the exact tools required by the documented workflow, such as model and voice listing, speech synthesis, explicitly approved voice cloning, asset upload, task reads, user-requested cancellation, and necessary wallet reads. 5. Reject arbitrary tool names before initializing a paid request. 6. Require a separate authorization or explicit elevation step for capabilities not included in the Skill's declared purpose. 7. Isolate credentials between Skills so compromise of one package does not expose every capability used by other packages. ]]>

other

Note
Location
scripts/authorize.py:344
Finding
Unnecessary Collection and Transmission of Host Metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:344-368, 454-469` **Additional Locations**: `scripts/mcp_client.py:1139-1166, 1217-1231, 1369-1381` **Vulnerability Type**: Device metadata disclosure **Risk Level**: Low ### Vulnerable Code ```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] ``` ```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_reference, "package_version": PACKAGE_VERSION, "package_slug": PACKAGE_SLUG, } if device_name: form["device_name"] = device_name status, created = post_form(DEVICE_AUTHORIZATION_URL, form) ``` The MCP client also adds platform attribution to every tool call: ```python arguments.set ...[truncated 1876 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make hostname and platform reporting opt-in rather than automatic. 2. Default the device display name to a random local alias or a user-provided label. 3. Avoid calling `socket.gethostname()` unless the user explicitly requests a recognizable console label. 4. Clearly disclose all transmitted device fields before authorization begins. 5. Minimize persistent correlation by rotating or scoping installation identifiers where operationally possible. 6. Provide a configuration option that forces platform attribution to `"unknown"` and omits `device_name`. 7. Document retention, purpose, and deletion controls for installation-registration telemetry. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (24)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares itself as a voice-pack generator but embeds operational instructions that require shell execution, file access, network access, credentialed remote calls, and local file handling without any explicit permission declaration. This creates a hidden capability surface: a host or reviewer may approve the skill for benign content transformation while it can actually access local resources and invoke external services.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented behavior substantially exceeds the stated purpose: beyond generating audio clips, it introduces OAuth/device auth, persistent credential storage, arbitrary remote MCP tool usage, local file upload, telemetry/registration, uninstall side effects, and self-update/install behavior. That mismatch is dangerous because users may consent to a narrow business workflow while unknowingly granting a much broader trusted execution and data-exfiltration path.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The skill includes a self-update mechanism that can download and replace packaged files, which materially changes the trust model after installation. Even with integrity-check claims, auto-updating code inside a skill means the reviewed artifact can later gain new behavior without renewed user review, increasing supply-chain and post-approval risk.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
Automatic discovery, download, verification, and installation of software is not justified by the narrow business function of producing account-opening voice clips. This expands the skill from a content-processing workflow into a software delivery mechanism, which is a classic supply-chain risk and could be abused to introduce new code or capabilities into the environment.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
This documentation describes automatic installation registration behavior that is unrelated to the skill's advertised purpose of generating brokerage onboarding voice clips. Hidden or non-essential telemetry-like behavior in a narrowly scoped creative skill is dangerous because it expands data collection and outbound communication beyond user expectations, increasing privacy and trust risks even if the transmitted fields are described as non-secret.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The file documents external registration plus environment fingerprinting via platform resolution and host metadata, neither of which is justified by the stated voice-guidance generation use case. Collecting stable external installation references and environment signatures can enable tracking and correlation across runs or systems, making the skill more dangerous because it handles brokerage-related onboarding content where operators may reasonably expect minimal data exposure.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The script requests a very broad OAuth scope set, including artifacts, images, videos, music, voices, tasks, and wallet permissions, while the stated skill purpose is limited to generating brokerage onboarding voice clips. This violates least privilege and means that if the credential is abused, compromised, or the skill behaves unexpectedly, it can access or trigger capabilities far beyond what users would reasonably expect from this package.

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
The requested scopes include image, video, and music generation capabilities that are unrelated to the described function of converting written account-opening steps into voice clips. These unnecessary privileges expand the blast radius of any compromise or misuse and indicate overbroad authorization design.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The requested scopes include image, video, and music generation capabilities that are unrelated to the described function of converting written account-opening steps into voice clips. These unnecessary privileges expand the blast radius of any compromise or misuse and indicate overbroad authorization design.

Context-Inappropriate Capability

Medium
Confidence
83% confidence
Finding
The code detects the host agent platform from environment variables and captures the local hostname for submission/storage during authorization. While not as severe as token overreach, this is host fingerprinting beyond what is necessary for simple voice clip generation and creates additional privacy and environment-discovery risk.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The client exposes broad capabilities far beyond the declared voice-clip function: generic MCP tool invocation, package self-update, upload handling, registration telemetry, and inventory recording. In the context of a narrowly described brokerage onboarding audio skill, this creates unnecessary remote control surface and violates least functionality, increasing the risk that the skill can be used as a general-purpose agent bridge rather than a single-purpose media tool.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The code downloads manifests and archives from remote infrastructure and then replaces local package files on disk, including its own client code. Even though there are several integrity checks, self-updating executable code is unusually dangerous for a skill whose stated purpose is generating account-opening voice clips, because compromise of the update channel or publisher instantly expands to code execution in the local environment.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The client records installation telemetry and a local skill inventory unrelated to the advertised function of converting written steps into audio clips. In a brokerage context, hidden or weakly disclosed telemetry is more sensitive because it can reveal installation footprint, platform identity, and operational metadata in environments likely subject to compliance and privacy expectations.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The CLI supports a generic remote tool runner that reads arbitrary JSON from stdin and forwards it to backend tools, rather than restricting operations to account-opening voice generation. In this skill context, that mismatch is especially dangerous because it effectively turns the package into a general backend RPC client capable of invoking whatever tools the remote service exposes under the user's authorization.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The uninstall script manages a shared Beatra device connection, including conditional revocation of remote OAuth/device authorization, which is unrelated to the advertised purpose of generating brokerage onboarding voice clips. Even if framed as cleanup logic, touching shared credentials and remote auth materially expands the skill’s privilege and attack surface; compromise or misuse could disconnect other skills on the device or remove shared state unexpectedly.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
This code constructs authenticated requests to a central revocation endpoint using a bearer token loaded from local credential storage. For a skill whose stated function is audio generation, direct credential use and remote OAuth revocation are unnecessary privileged behaviors and create a path for account/device disruption if the script is invoked maliciously or bundled deceptively.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The document explicitly states that the client performs silent automatic update checks and installs newer releases without separate user confirmation. Even with integrity checks and rollback protections, modifying installed software by default without a prominent opt-in or clear warning weakens user control and can create supply-chain and operational risk if the update source, signing pipeline, or release process is ever compromised.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The markdown states that the bundled client automatically performs a registration call on first use, but it does not present an explicit user warning or consent mechanism for that data transmission. Silent outbound calls are risky because users may be unaware that package, version, platform, and installation reference data are being sent, which undermines transparency and may violate privacy expectations or enterprise controls.

Missing User Warnings

Low
Confidence
72% confidence
Finding
The script persists host metadata (`platform` and possibly `device_name`) to disk without any visible user-facing disclosure in this file. Although the stored data is limited, silently writing environment-identifying metadata can violate user expectations and makes the broader over-collection behavior harder to detect.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
maybe_auto_update() performs silent background replacement of installed package files before normal commands proceed, without an immediate user-facing confirmation at execution time. Silent code mutation reduces transparency and can make incident response or change control difficult, particularly in enterprise or regulated brokerage environments where operators expect deterministic tooling.

Credential Access

High
Category
Privilege Escalation
Content
scope = _required_string(polled, "scope")
            if set(scope.split()) != set(SCOPE.split()):
                raise RuntimeError("Beatra authorization returned an unsupported scope")
            credential_path = state_dir / "credentials.json"
            _atomic_json(
                credential_path,
                {
Confidence
93% confidence
Finding
The script stores a bearer access token in `credentials.json`, and because the token is granted highly overbroad scopes, compromise of that file would provide powerful unauthorized access. The storage mechanism uses restrictive permissions, but the real issue is that a long-lived local credential with excessive privileges is being created for a narrowly described skill.

Credential Access

High
Category
Privilege Escalation
Content
#: these and then removes the directory only if it is empty — the script
#: never recursively deletes a directory it does not fully understand.
_STATE_FILES = (
    "credentials.json",
    "installation.json",
    "host.json",
    "skills.json",
Confidence
88% confidence
Finding
Referencing shared state files including credentials.json indicates the package is designed to manipulate authentication-related material outside its functional scope. Even though this line is just a filename constant, in context it supports later deletion of shared auth state and therefore contributes to risky credential handling that can affect all installed skills.

Credential Access

High
Category
Privilege Escalation
Content
def _device_token(state_dir: Path) -> str | None:
    path = state_dir / "credentials.json"
    try:
        value = json.loads(path.read_text(encoding="utf-8"))
    except (OSError, ValueError):
Confidence
98% confidence
Finding
The _device_token function reads an access token from ~/.beatra/credentials.json for use in authenticated revocation requests. Reading bearer tokens from shared local storage is a privileged credential-access pattern that is not justified by the skill’s declared audio workflow and could be abused to revoke device authorization or facilitate further token misuse.

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
95% confidence
Finding
The package explicitly includes self-update capability that can modify installed code, which is a self-modification primitive. In a skill that should only generate onboarding voice clips, this is unjustified and materially raises risk because any flaw or compromise in the update trust chain results in persistent local code replacement.

Static analysis

No suspicious patterns detected.