Back to skill

Security audit

Customer Onboard Voice Pack

Security checks for vulnerabilities and agentic risk

Overview

The skill performs the advertised voice-generation workflow, but it also grants broad Beatra account powers and silently self-updates, so it belongs in Review before installation.

Install only if you are comfortable linking a Beatra account, storing a reusable device token in ~/.beatra, allowing paid remote media operations, and accepting default silent package updates. Review the Beatra approval scopes carefully, disable auto-updates with the documented command if you want manual control, and avoid installing if you expected a voice-only, narrowly scoped credential.

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

Error
Location
scripts/authorize.py:35
Finding
Overprivileged Device Token and Unrestricted MCP Tool Dispatch## Vulnerability Details **File Location**: `scripts/authorize.py:35-39`; `scripts/mcp_client.py:1463-1482` **Vulnerability Type**: Excessive authorization scope and missing tool allowlist **Risk Level**: High ### Vulnerable Code `scripts/authorize.py:35-39`: ```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" ) ``` `scripts/mcp_client.py:1463-1482`: ```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 create customer-onboarding voice clips and, when explicitly requested, clone a voice from an authorized sample. The requested OAuth scope nevertheless includes unrelated image, video, and music generation capabilities. It also grants credit spending and task cancellation. The bundled client accepts any caller-provided MCP tool name and forwards it through `tools/call`. There is no package-specific allowlist limiting execution to the tools required by the documented voice workflow. Consequently, the effective authorization boundary is the broad server-issued token rather than the narrower set of op ...[truncated 1675 chars]
Remediation
## Remediation Suggestions 1. Replace the shared full-scope token with a package-specific token limited to the voice workflow. 2. Remove `images:generate`, `videos:generate`, and `music:generate`. 3. Grant only the narrowly required speech, voice, model-discovery, upload, artifact-read, and task-read capabilities. 4. Separate wallet spending and task cancellation into explicit, user-approved elevation steps if those privileges are ever required. 5. Add a strict local MCP tool allowlist, for example: - `beatra.models.list` - `beatra.voices.list` - `beatra.voices.clone` - `beatra.speech.synthesize` - `beatra.assets.upload` - `beatra.tasks.get` - `beatra.tasks.list` - Required read-only wallet operations 6. Reject every unrecognized tool name before loading or transmitting credentials. 7. Ensure server-side policy independently enforces the same package-specific allowlist. 8. Use separate credentials for different installed Skills rather than sharing one full-scope token.

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Silent Remote Code Retrieval and Package Replacement Enabled by Default## Vulnerability Details **File Location**: `scripts/mcp_client.py:516-522`, `scripts/mcp_client.py:969-1018`, `scripts/mcp_client.py:1541-1544` **Vulnerability Type**: Automatic remote payload retrieval and executable replacement **Risk Level**: High ### Vulnerable Code `scripts/mcp_client.py:516-522`: ```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 ``` `scripts/mcp_client.py:969-1018`: ```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 ): ...[truncated 4340 chars]
Remediation
## Remediation Suggestions 1. Disable automatic installation by default. Update checks may be informational, but code replacement should require explicit user approval. 2. Verify release metadata with a publisher public key embedded independently in the audited package. 3. Use a signed update framework such as TUF, including signed root, targets, snapshot, and timestamp metadata with rollback and freeze-attack protections. 4. Separate discovery hosting from the signing authority so compromise of the web or CDN publication path cannot produce trusted releases. 5. Consider threshold signatures and offline release keys for executable package updates. 6. Display the target version and verified publisher identity before installation. 7. Prefer host-managed immutable package updates so the Skill cannot replace its own executable code. 8. Preserve the existing archive bounds, path validation, ownership checks, transaction journal, and rollback logic as defense-in-depth. 9. Ensure update-state corruption fails closed to `auto_update: false`, rather than silently restoring automatic installation. 10. Re-audit or attest the newly installed package before it receives access to credentials or paid MCP operations.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (26)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares a narrow content-generation purpose, but its instructions require broad capabilities including shell execution, local file access, network access, and file writes without any declared permission boundary. That mismatch is dangerous because it enables credential handling, local state modification, remote calls, and uploads that a user would not reasonably infer from the skill metadata, increasing the chance of over-privileged execution and unauthorized data exposure.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented purpose is creating onboarding voice clips, but the skill also introduces unrelated high-risk behaviors: OAuth/device login, bearer token storage in ~/.beatra, arbitrary local file upload, a generic remote tool client, telemetry/registration, uninstall logic, and self-update/install flows. This hidden expansion of scope defeats informed consent and materially changes the trust model, because a user invoking a media-generation skill may unknowingly authorize credential persistence, code/package changes, and broader remote operations.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The skill includes automatic self-update and installation behavior that is not necessary for fulfilling the immediate task of generating onboarding voice clips. Any mechanism that can replace package-owned files at runtime expands the attack surface substantially; if the update channel, signing, or verification process is ever bypassed or misconfigured, the skill becomes a code-delivery path rather than a narrowly scoped content tool.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The documentation instructs the agent to persist a long-lived installation identity and device token in user files that are unrelated to the stated purpose of generating onboarding voice clips. This creates durable authentication state to an external service, expanding the skill's privileges and persistence in a way that is unnecessary for the advertised local content-transformation workflow.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The file requires Python execution and live HTTPS communication with a remote MCP service even though the skill is described as converting written onboarding steps into voice clips. That mismatch indicates hidden networked behavior and creates an unexpected path for data exfiltration, remote control, or unauthorized account linkage.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The bulk of the skill behavior is devoted to authorizing against Beatra, maintaining a device token, and invoking remote MCP tools across broad capabilities such as image, video, music, speech, upload, model, and task tools. This is materially different from the advertised onboarding voice-clip function and suggests the skill is a wrapper for broad remote platform access rather than a narrowly scoped media utility.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The requested OAuth scope is far broader than the skill’s stated purpose of generating onboarding voice clips. It includes unrelated capabilities such as artifact access, image/video/music generation, task control, and wallet spending, violating least privilege and creating a large blast radius if the credential is misused or the skill is compromised.

Context-Inappropriate Capability

Critical
Confidence
95% confidence
Finding
Granting task read and cancellation privileges is not justified by the described voice-clip generation workflow and could let the skill inspect or interfere with other queued or running work. In a shared account context, this may expose metadata about unrelated jobs or disrupt legitimate operations.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
Granting task read and cancellation privileges is not justified by the described voice-clip generation workflow and could let the skill inspect or interfere with other queued or running work. In a shared account context, this may expose metadata about unrelated jobs or disrupt legitimate operations.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
Granting task read and cancellation privileges is not justified by the described voice-clip generation workflow and could let the skill inspect or interfere with other queued or running work. In a shared account context, this may expose metadata about unrelated jobs or disrupt legitimate operations.

Context-Inappropriate Capability

Medium
Confidence
79% confidence
Finding
The script collects and persists host platform and device hostname information in local state. While this appears intended for inventory and UX, it exceeds what is obviously necessary for a simple voice-clip generator and creates additional local fingerprinting data that could aid profiling or leak environment details if the state directory is exposed.

Description-Behavior Mismatch

High
Confidence
90% confidence
Finding
The client implements broad capabilities unrelated to generating onboarding voice clips, including self-update, installation registration, and local inventory management. In this skill context, that mismatch is dangerous because it expands trust and persistence far beyond the declared purpose, creating an unnecessary supply-chain and surveillance surface inside the user's environment.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The code fingerprints the host environment by inspecting agent-specific environment variables and local host metadata, then uses that platform label in outbound requests. For a voice-generation skill, this collection is not clearly necessary, and it increases privacy risk and can aid downstream targeting or environment-specific behavior without informed user consent.

Context-Inappropriate Capability

High
Confidence
92% confidence
Finding
The client persistently records local skill inventory and installation telemetry, including install path and platform, despite that behavior being unrelated to the stated onboarding-voice function. This creates unnecessary local tracking and external reporting, and the persistence makes the behavior more dangerous because it survives across runs and can influence uninstall or lifecycle decisions.

Intent-Code Divergence

Medium
Confidence
76% confidence
Finding
The code comments describe registration as best-effort telemetry that should not block the requested operation, but the function first performs a persistent local inventory write on every use. That discrepancy is risky because it obscures state-changing behavior behind a benign framing, reducing transparency and making users more likely to run code that modifies local metadata unexpectedly.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
This uninstall script manages and conditionally revokes a shared Beatra device credential stored under ~/.beatra, which is unrelated to the advertised function of producing onboarding voice clips. Even if framed as cleanup, giving a content-generation skill authority over shared credentials creates an unnecessary trust boundary violation and can disrupt other installed skills or the host’s platform access.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The _default_post_revoke function sends the bearer token from shared credentials to a remote revoke endpoint, allowing this skill’s uninstall flow to invalidate the device authorization for the entire Beatra installation. That capability is not justified by the skill’s stated purpose and could be abused to cause denial of service for other skills or sever platform connectivity.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The _STATE_FILES list targets shared files in ~/.beatra, including credentials, host state, registrations, and the skill inventory. Deleting shared platform state from a single skill’s uninstall path can remove authentication material and operational metadata for unrelated skills, causing loss of access and broader application instability.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The skill states that newer versions install automatically without separate confirmation, but this risk is not prominently disclosed near the main execution instructions or in the skill description. Even if the update mechanism is intended to be safe, silent code changes undermine user expectations and make consent ineffective, especially for a skill that also uses shell, filesystem, and network capabilities.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The document states that the client silently checks for updates and automatically installs newer versions without separate confirmation. Even with integrity checks and fixed update sources, unattended code replacement changes the local executable state without an explicit user approval step at install time, which increases supply-chain and operational risk if the update channel, signing process, or release pipeline is ever compromised.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The client can silently self-update and replace installation files during normal operation without a contemporaneous user-facing prompt. Even though the update flow includes checksum and path validations, silent code replacement is still dangerous in a skill whose declared purpose is voice generation, because it introduces hidden supply-chain risk and unexpected behavior changes at runtime.

Credential Access

High
Category
Privilege Escalation
Content
- `~/.beatra/installation.json` contains one stable, non-secret installation
  reference.
- `~/.beatra/credentials.json` contains the single Device Token.

On POSIX systems the directory must be mode `0700` and both files mode `0600`.
On Windows the current user must be the only principal granted access through
Confidence
96% confidence
Finding
The skill explicitly manages and stores a reusable device token in a local credentials file, giving the skill ongoing authenticated access to an external account. In the context of a skill advertised for onboarding voice clips, credential acquisition and persistence are unjustified and materially increase the risk of unauthorized account access if the skill is abused or the file is exposed.

Credential Access

High
Category
Privilege Escalation
Content
4. polls every 5 seconds for up to 15 minutes while the user signs in (or
   creates their account) and selects Allow;
5. atomically saves the returned Device Token to
   `~/.beatra/credentials.json` without printing an HTTP response body;
6. validates the new credential with the same non-billable MCP request and
   prints Ready only after it succeeds.
Confidence
96% confidence
Finding
The documentation directs the helper to save a returned device token to disk, creating persistent authenticated access after a one-time approval. Combined with the mismatch between the stated voice-clip purpose and the broad remote MCP capabilities, this persistence materially raises the likelihood of account misuse beyond the user's expectations.

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
92% confidence
Finding
Referencing credentials.json as part of the files to unlink shows the script is designed to remove shared authentication state. In the context of a voice-pack skill, touching credential storage is unjustified and dangerous because it can disable shared access used by other components and expands the skill’s authority into credential lifecycle management.

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
94% confidence
Finding
The _device_token function reads an access token from shared credentials.json so it can be used for remote revocation. Accessing bearer tokens from a skill whose purpose is audio generation is an unnecessary credential-access capability that broadens the blast radius of compromise and enables disruption of the host’s shared authorization.

Static analysis

No suspicious patterns detected.