Back to skill

Security audit

sales-voicemail-pack

Security checks for vulnerabilities and agentic risk

Overview

The skill does make sales voicemail audio, but it also installs a broad shared Beatra client with silent self-updates, broad account scopes, shared credential handling, telemetry, and uninstall actions that exceed a narrowly described voicemail skill.

Review this skill before installing. It is not just a voicemail generator: it connects your device to Beatra with a shared bearer token, can spend credits for generation, can upload authorized voice samples, registers installation metadata, silently updates package files by default, and may revoke/delete shared Beatra state during uninstall when it believes this is the last Beatra skill. Install only if you are comfortable with those Beatra platform behaviors, and consider disabling automatic updates with the documented update --auto off command after installation.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (2)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/authorize.py:35
Finding
Voicemail Skill Requests Excessive OAuth Privileges and Permits Arbitrary MCP Tool Calls<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:35-38`; `scripts/mcp_client.py:1461-1485` **Vulnerability Type**: Excessive authorization scope and unrestricted remote tool dispatch **Risk Level**: Medium ### Vulnerable Code The authorization helper requests capabilities unrelated to voicemail generation: ```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 generic command dispatcher accepts any caller-supplied MCP tool name without applying a Skill-specific allowlist: ```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}, ) ``` The command-line interface exposes the unrestricted tool name directly: ```python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name") ``` ### Technical Analysis The Skill’s declared functionality requires text-to-speech generation, optional voice cloning, explicit sample upload, voice and model discovery, task inspection, and limited billing information. The requested bearer-token scope additionally grants image, video, and music generation, general artifact access, wallet spending, and task cancellation. ...[truncated 1980 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared broad scope with a least-privilege scope limited to: - Text-to-speech generation. - Voice and model lookup. - Optional voice cloning only when requested. - Explicit artifact upload for authorized voice samples. - Task status and result retrieval. - Read-only wallet balance and ledger operations where required. 2. Remove unrelated permissions such as image, video, and music generation from this Skill’s authorization request. 3. Avoid granting general wallet spending and task cancellation unless a specific documented workflow requires them. 4. Introduce a Skill-specific allowlist in `_run_command`, for example: - `beatra.models.list` - `beatra.voices.list` - `beatra.voices.clone` - `beatra.speech.synthesize` - `beatra.assets.upload` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.wallet.get` - `beatra.wallet.ledger` 5. Reject all tools not explicitly permitted for this package before initiating the MCP request. 6. Use separate authorization grants for optional high-risk capabilities, such as voice cloning or task cancellation. 7. Require explicit user confirmation immediately before paid or destructive operations, independently of the initial device authorization. 8. Prefer per-package credentials over a shared bearer credential so compromise of one Skill does not expose unrelated Beatra capabilities. ]]>

T09 · Insecure Skill Coding Practices

Note
Location
scripts/mcp_client.py:1044
Finding
Windows Credential Confidentiality Relies on Unverified Inherited ACLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:122-129`; `scripts/mcp_client.py:1044-1052` **Vulnerability Type**: Sensitive credential file stored without enforcing or validating Windows access controls **Risk Level**: Low ### Vulnerable Code Credential-directory restrictions are explicitly applied only on POSIX systems: ```python def _private_directory(path: Path) -> None: # POSIX gets explicit 700/600. On Windows the state directory lives under # the user profile, whose default ACL is already private to the user — # the same posture as gh/aws/gcloud credential stores. The former custom # DACL ceremony was dropped deliberately: its command patterns read as # hostile to agent safety policies and endpoint security, failing installs # while adding no protection an elevated administrator could not bypass. path.mkdir(mode=0o700, parents=True, exist_ok=True) if os.name == "posix": path.chmod(0o700) ``` When reading credentials on Windows, the client trusts the existing profile ACL without checking it: ```python def _read_private_credentials(state_dir: Path, path: Path) -> str: if os.name == "nt": # The state directory lives under the user profile, whose default # ACL is already private to the user (the gh/aws/gcloud posture). # The former custom DACL verification was dropped deliberately: its # command patterns read as hostile to agent safety policies and # endpoint security, failing installs while adding nothing an # elevated administrator could not bypass. return path.read_text(encoding="utf-8") ``` This differs from the POSIX branch, which validates directory ownership, directory mode, file ownership, file mode, and regular-file status before reading the token. ### Technical Analysis The documentation states that the current Windows user must be the only principal granted access to the credential file. The implementation does no ...[truncated 2128 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Create `~/.beatra` and `credentials.json` with an explicit Windows DACL that grants access only to the current user and required system principals. 2. Disable or carefully constrain inherited permissions on the credential file. 3. Before reading the token, inspect the effective ACL and reject credentials readable by unintended principals. 4. Perform ACL configuration through native Windows APIs or a well-reviewed security abstraction rather than constructing shell commands. 5. Store the bearer token in a platform credential vault, such as Windows Credential Manager or DPAPI-protected storage, instead of relying solely on filesystem ACLs. 6. Detect existing credential files with unsafe ACLs and require reauthorization after securely removing or migrating them. 7. Update the documentation so its Windows confidentiality guarantee matches the enforcement implemented in code. 8. Reduce the token’s OAuth scope so that any credential disclosure has a smaller account and billing impact. ]]>
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 (19)

Lp3

Medium
Category
MCP Least Privilege
Confidence
94% confidence
Finding
The skill declares no permissions while explicitly instructing use of shell execution, network calls, local file inspection/upload, package updates, and on-disk replacement. This creates a transparency and consent failure: a user or host may treat the skill as low-risk while it actually has broad operational capability, increasing the chance of unauthorized file, credential, or network actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared purpose is narrow audio generation, but the documented behavior adds authentication, credential storage, arbitrary Beatra MCP tool invocation, local file upload, installation registration/telemetry, uninstall cleanup, and self-updating package replacement. That mismatch is dangerous because it hides materially broader trust boundaries and allows sensitive side effects unrelated to the user-visible task.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The skill includes a self-update mechanism that downloads new releases and replaces package-owned files automatically, yet this behavior is absent from the core manifest description. Undisclosed code replacement materially changes the security posture because future behavior can change without the same review or user awareness that applied to the original installed skill.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Automatic download and on-disk replacement are not necessary to turn text scripts into voicemail clips, so they expand the attack surface without clear functional justification. If the update path, discovery service, CDN, or verification logic is compromised, the skill becomes a delivery channel for arbitrary new behavior under the guise of routine audio generation.

Description-Behavior Mismatch

Medium
Confidence
83% confidence
Finding
The changelog references unrelated balance, ledger, tier pricing, and top-up behavior that does not match a voicemail-generation skill. This mismatch is a supply-chain trust and scope-transparency problem: it can indicate hidden capabilities, repurposed code, or undisclosed backend actions that users would not reasonably expect from the stated functionality.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The authorization helper requests a very broad OAuth scope set, including images, videos, music, voice management, artifact/task access, and wallet spending, which far exceeds the stated purpose of converting seller-provided voicemail scripts into spoken voicemail clips. This violates least-privilege and creates substantial blast radius: if the credential is misused or the skill is compromised, it could trigger unrelated generation capabilities and spend wallet-backed resources.

Context-Inappropriate Capability

Medium
Confidence
81% confidence
Finding
The code persists host platform, device hostname, and a local inventory of installed skill paths even though that metadata is not obviously necessary for simple voicemail clip generation. This expands data collection beyond the skill's described purpose and may expose sensitive environment details such as workstation names, agent type, and filesystem layout to other local components or future exfiltration paths.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The file implements broad behaviors unrelated to a voicemail-generation skill, including self-update, installation registration, local inventory tracking, credential handling, and remote MCP command plumbing. In the context of a narrowly described sales-voicemail package, this unnecessary capability expansion increases the trust boundary and creates a supply-chain and surveillance risk surface far beyond the advertised purpose.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The code fingerprints the host environment using environment variables and local host metadata, then injects that platform identity into outbound tool calls and registration telemetry. For a voicemail-pack skill, this collection is not necessary to perform the stated function and creates avoidable privacy leakage and host profiling risk to the remote service.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The client maintains a device-local inventory of installed skills and performs remote installation registration, which is unrelated to converting scripts into voicemail clips. This creates unnecessary local surveillance metadata and external telemetry that could reveal user behavior, installed tooling, and environment details if misused or breached.

Description-Behavior Mismatch

High
Confidence
94% confidence
Finding
This uninstall script performs device-token revocation against a remote API and participates in removing shared Beatra state, capabilities that are unrelated to the advertised voicemail-generation function and materially affect account/device authorization. Even though the code is cautious and appears intended to safely uninstall a shared integration, bundling credential lifecycle management into a content-generation skill increases blast radius: executing the script can disconnect other installed skills or alter shared account state if inventory assumptions are wrong or manipulated.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The code deletes files in ~/.beatra including credentials, installation, host, skills, and registration state, which are explicitly described as shared across skills. Any flaw in survivor detection, local tampering of skills.json, or misuse of this script could remove shared state and break unrelated skills or disconnect the device from the service.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
Reading an access token from credentials.json gives this skill package access to device authorization material despite the package's stated purpose being voicemail clip generation. Although the token is used for uninstall revocation rather than obvious exfiltration, unnecessary access to bearer credentials expands the attack surface and enables account-affecting actions if the script is modified, repurposed, or invoked unexpectedly.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The document explicitly states that the client performs silent update checks and automatically installs newer versions without separate confirmation. Even with integrity checks and rollback protections, this behavior modifies local files without an upfront, per-action user warning or consent, which creates a supply-chain and user-trust risk if the update source, signing process, or release pipeline is ever compromised.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The code performs automatic silent self-updates that can replace installed package files during normal execution without contemporaneous user confirmation. Even with checksum and manifest validation, this grants remote package infrastructure the ability to modify executable client code, which is especially risky for a skill whose declared purpose does not require self-modifying behavior.

Credential Access

High
Category
Privilege Escalation
Content
},
  "mcp": {
    "authentication": "device-bearer",
    "credential_file": "~/.beatra/credentials.json",
    "name": "beatra",
    "transport": "streamable-http",
    "url": "https://mcp.beatra.ai/mcp"
Confidence
91% confidence
Finding
The manifest explicitly points the skill at a local bearer-token credential file and configures remote MCP access over HTTP streaming. Any skill that can trigger use of those credentials to contact a remote service creates a meaningful secret-handling and overreach risk, especially when the skill's stated purpose is only voicemail generation and does not justify broad account access.

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
86% confidence
Finding
The presence of credentials.json in the set of files managed by the script indicates the package is designed to touch shared credential material. In context, this is not mere incidental string usage: the script later reads and deletes that credential file, which is a privileged capability beyond the expected scope of a voicemail skill.

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
93% confidence
Finding
This function reads the bearer access token from ~/.beatra/credentials.json so it can call the remote revoke endpoint. Access to live bearer tokens is sensitive by itself, and in a skill whose advertised role is generating voicemail audio, that capability is unjustified and could be abused to revoke authorizations or support future 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
96% confidence
Finding
Exposing self-update functionality in the CLI confirms the package can modify its own installed code. In a skill advertised as a voicemail-content tool, self-modification is a dangerous mismatch because compromise of the update channel or abuse of the feature can transform a benign content skill into an arbitrary code delivery mechanism.

Static analysis

No suspicious patterns detected.