Back to skill

Security audit

Visitor Desk Voice Pack

Security checks for vulnerabilities and agentic risk

Overview

This skill performs the advertised voice-generation workflow, but it also grants and uses broad account, update, telemetry, and shared-credential capabilities that exceed a simple visitor-desk voice tool.

Review this before installing in a sensitive or managed environment. It connects to Beatra, stores a shared bearer credential in ~/.beatra, can spend account credits when user-approved tool calls are made, uploads user-selected files for cloning, sends installation/platform metadata, and silently updates its own package files unless automatic updates are disabled with the documented command.

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
  • 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
Findings (4)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Silent Default-On Remote Package Update Permits Post-Audit Code Replacement<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:969-1017`, `scripts/mcp_client.py:1541-1544`, `SKILL.md:190-203` **Vulnerability Type**: Default-on remote payload retrieval and package code replacement **Risk Level**: Critical ### Code Snippet ```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=resolved_root, update_home=update_home, get_bytes=get_bytes, ) discovery = checked["discovery"] manifest, new_files = download_update(discovery, get_bytes=get_bytes) _apply_update( ...[truncated 3230 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. Require explicit, informed user approval before replacing executable files. 2. Separate update checking from update installation. A routine business command may check for an available version, but it should not install it silently. 3. Sign release manifests with a dedicated offline release key and pin the corresponding public key in the installed client. 4. Verify signatures over the package name, channel, version, complete file manifest, archive digest, and expiration metadata. 5. Use key rotation metadata that is itself signed by an already trusted key. 6. Display the current version, proposed version, changed files, source, and signature identity before installation. 7. Preserve the existing checksum, archive-safety, ownership, transaction, and rollback protections as defense-in-depth. 8. Consider delegating updates to the host platform’s trusted package manager rather than implementing self-modifying application code. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:31
Finding
Reception Voice Skill Requests Broad Unrelated Account Permissions and Allows Arbitrary Tool Dispatch<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:31-35`, `scripts/mcp_client.py:1463-1481` **Vulnerability Type**: Excessive OAuth scope combined with unrestricted MCP tool selection **Risk Level**: High ### Code Snippet The authorization helper requests capabilities beyond visitor-reception speech 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 command dispatcher accepts any caller-supplied MCP tool name: ```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 declared functionality requires text-to-speech generation, voice/model discovery, task polling, and optionally voice cloning and upload. It does not require general image generation, video generation, music generation, unrestricted artifact access, broad task cancellation, or an undifferentiated wallet-spending capability. The authorization helper nevertheless requests all of these scopes in one shared bearer credential. The local MCP client then accepts an arbitrary `tool_name` from its command line and forwards it to `tools/call` without enforcing a package-specific allowlist. This combi ...[truncated 1680 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the broad scope with the minimum permissions required for visitor-reception speech: - Text-to-speech generation. - Voice and model listing. - Required task creation and task-status reads. - Narrow artifact reads for generated outputs. 2. Request voice-cloning and upload permissions only when the user explicitly selects the optional cloning workflow. 3. Remove image, video, and music generation scopes from this package. 4. Avoid a generic wallet-spending scope where the service supports capability-specific billing authorization. 5. Implement a package-local tool allowlist in `_run_command()`. Reject any tool not required by the documented workflow. 6. Use separate allowlists for the default speech flow and optional clone/upload flow. 7. Bind server-side authorization to both the package identity and permitted tool set; do not rely only on client-side controls. 8. Issue separate per-package or per-capability tokens instead of sharing one full-scope token across all Beatra Skills. 9. Log safe operation metadata for user review without logging bearer tokens, prompts, or sensitive content. ]]>

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/authorize.py:340
Finding
Authorization Collects and Transmits Hostname and Agent-Environment Identifiers<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:340-370`, `scripts/authorize.py:463-480`, `scripts/mcp_client.py:1149-1165`, `scripts/mcp_client.py:1218-1227` **Vulnerability Type**: Environment reconnaissance and persistent device telemetry beyond core media-generation needs **Risk Level**: Medium ### Code Snippet The authorization helper inspects environment variables to identify the host agent: ```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] ``` The collected values are included in authorization data: ```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": PACKAG ...[truncated 2538 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not collect or transmit the system hostname by default. 2. Use a generic label such as `Visitor Desk Voice Pack` or a locally generated non-identifying alias for the device list. 3. Make hostname sharing and telemetry opt-in through a clear authorization prompt. 4. Disclose every transmitted telemetry field, its purpose, retention period, and deletion mechanism. 5. Minimize platform detection to a caller-provided value where source attribution is genuinely required. 6. Avoid sending platform attribution on every business call; registration-time attribution is sufficient for most analytics. 7. Rotate or scope the stable installation reference where long-term cross-operation correlation is unnecessary. 8. Provide controls to inspect and delete locally cached telemetry in `host.json` and `registrations.json`. 9. Ensure server-side logs do not retain hostname or installation attribution longer than operationally necessary. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mcp_client.py:231
Finding
Voice-Sample Upload Accepts Server-Directed HTTPS Destinations Without a Host Allowlist<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:231-265`, `scripts/mcp_client.py:1428-1461` **Vulnerability Type**: Insufficient validation of a remote upload destination **Risk Level**: High ### Code Snippet The MCP response supplies the upload URL and headers: ```python def _complete_upload( result: dict[str, Any], *, mime_type: str, content: bytes, put_bytes: PutBytes, ) -> dict[str, str]: structured = result.get("structuredContent") instruction = structured.get("upload") if isinstance(structured, dict) else None if not isinstance(instruction, dict) or instruction.get("method") != "PUT": raise RuntimeError("Beatra upload instructions are invalid") url = instruction.get("url") headers = instruction.get("headers") if not isinstance(url, str) or not isinstance(headers, dict): raise RuntimeError("Beatra upload instructions are invalid") parsed = urllib.parse.urlsplit(url) if ( parsed.scheme != "https" or not parsed.hostname or parsed.username is not None or parsed.password is not None or parsed.fragment ): raise RuntimeError("Beatra upload instructions are invalid") if not all(isinstance(key, str) and isinstance(value, str) for key, value in headers.items()): raise RuntimeError("Beatra upload instructions are invalid") content_type = _header_value(headers, "Content-Type") content_length = _header_value(headers, "Content-Length") if content_type != mime_type or content_length != str(len(content)): raise RuntimeError("Beatra upload instructions are invalid") response = put_bytes(url, dict(headers), content) artifact_id = response.get("artifact_id") if not isinstance(artifact_id, str) or not artifact_id: raise RuntimeError("Beatra upload returned an invalid response") return {"type": "artifact", "artifact_id": artifact_id} ``` The local file is read before req ...[truncated 3402 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce an exact allowlist of approved Beatra-controlled upload hostnames. 2. Avoid permissive suffix checks. If subdomains are needed, validate DNS names against an explicit, narrowly scoped suffix and reject lookalike domains. 3. Require the upload URL path to match the expected storage-provider and tenant pattern. 4. Cryptographically sign upload grants and verify them locally using a pinned public key. 5. Bind the signed grant to: - The exact destination URL. - HTTP method. - Artifact request identifier. - File size and MIME type. - Cryptographic digest of the content. - A short expiration timestamp. 6. Reject unexpected request headers, especially authorization or forwarding headers not required by the approved storage provider. 7. Resolve and validate destinations against private, loopback, link-local, and otherwise prohibited network ranges where applicable. 8. Add a user-visible destination disclosure before sensitive voice-sample uploads. 9. Preserve the existing regular-file, no-follow, size, stability, MIME-type, and content-length checks. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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
Findings (22)

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill exposes substantial capabilities—shell, network access, file read/write, and environment access—without declaring permissions or surfacing them in the manifest. That reduces informed consent and makes it harder for users or platforms to evaluate the real trust boundary, especially since the skill can invoke a bundled client that performs remote operations and local package changes.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The stated purpose is narrow voice-pack generation, but the documented behavior includes credential storage, browser-based auth, arbitrary remote tool invocation via MCP, local file upload, telemetry/registration, uninstall/revocation, and automatic software updates. This mismatch is dangerous because users may authorize the skill expecting simple media generation while actually granting a much broader software agent with persistent access and code-change capability.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The bundled client is allowed to automatically download and install newer releases, replace package-owned files, and persist that behavior without separate confirmation. Any auto-update mechanism materially expands the attack surface: compromise of the update channel, signing, packaging, or discovery flow could turn a voice skill into a code execution and persistence vector on the host.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The manifest presents a content-generation skill, but the execution instructions include wallet/account access, billing inspection, connection management, update controls, and software maintenance operations beyond creating clips. This broadens the skill's effective authority and increases the chance that a user invokes a business workflow tool that also performs sensitive account and host-management actions.

Description-Behavior Mismatch

High
Confidence
94% confidence
Finding
The document describes automatic installation registration to an external service and collection of package, version, platform, and a stable external installation reference, which is unrelated to the stated purpose of generating visitor reception voice clips. This creates an unjustified telemetry channel and host identification surface, increasing privacy and supply-chain risk if users install the skill expecting only local media generation behavior.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The documented behavior includes external registration plus platform resolution from environment signatures or a host file written at authorization time, which amounts to environment fingerprinting beyond the expected function of a voice-pack generation skill. In this context, collecting and persisting host/environment identity data is especially suspicious because it is not needed to split scripts into labeled audio clips and could enable tracking, inventorying, or correlation of installations across systems.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The OAuth scope set is far broader than the skill’s stated purpose of generating visitor reception voice clips. It includes unrelated capabilities such as images/videos/music generation, artifact/task control, voices write access, and wallet spending, so a stolen or misused token could be used to perform actions well beyond the expected audio workflow. In this skill context, the mismatch between requested privileges and the manifest description materially increases risk.

Context-Inappropriate Capability

Medium
Confidence
83% confidence
Finding
The script fingerprints the host agent environment and captures the device hostname, then transmits that metadata during authorization. For a narrowly described voice-pack skill, this data collection is not obviously necessary and can expose workstation identity, agent usage, or deployment details that aid profiling or targeting. The extra collection is more suspicious because it is outside the user-facing function of producing voice clips.

Description-Behavior Mismatch

Medium
Confidence
79% confidence
Finding
The authorization flow maintains a persistent local inventory of installed skills and their installation paths. That behavior exceeds the stated purpose of converting scripts into voice clips and creates an additional data store that can reveal what is installed and where, which may be sensitive in managed or multi-tool environments. While local-only, it expands the skill’s footprint and could assist later reconnaissance if the host is compromised.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The file exposes a generic MCP client capable of arbitrary tool listing and invocation, plus upload and update operations, while the advertised skill is narrowly about generating visitor reception voice clips. This mismatch materially expands the trust boundary and enables networked actions unrelated to the declared purpose, making abuse or unexpected capability exposure more likely.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The code downloads manifests and archives, validates them, and then replaces local installation files, which gives the package self-modifying behavior unrelated to producing voice clips. Even with integrity checks, silent code replacement increases supply-chain risk and turns any compromise of the update channel, signing/distribution process, or trusted origin into code execution inside the agent environment.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The code fingerprints the host environment and sends installation telemetry, which is not necessary for the declared voice generation function. In a skill context, collecting platform identifiers and installation references without clear user expectation increases privacy risk and creates unnecessary outbound data flow that could aid tracking or profiling.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This uninstall script manipulates a shared Beatra device connection and can influence credentials used by other skills, which is materially outside the declared purpose of generating visitor reception voice clips. A package with an unrelated business function should not own logic that inspects or affects shared authentication state, because it expands trust and creates an opportunity for service disruption or credential handling abuse during uninstall.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The code performs a network POST to revoke device authorization using a bearer token, giving this skill the ability to disable a shared account/device connection. In the context of a visitor desk voice generation skill, that capability is unjustified and dangerous because a compromised or overly broad uninstall path can cause denial of service for unrelated skills and accounts.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The script enumerates and later deletes files in ~/.beatra including credentials, installation, host, skills, and registrations state, which are explicitly shared across Beatra skills. Even though the code tries to preserve state when other skills remain, this is still sensitive cross-skill state manipulation that exceeds the permissions expected for a voice-pack skill and can break other installed functionality if assumptions are wrong.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill discloses automatic package updates only deep in the document, while the front-facing description does not clearly warn that code may be installed without separate confirmation. Hidden or under-emphasized auto-update behavior undermines informed consent and increases the chance that users run software that can materially change after approval.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The document states that the client silently checks for updates and automatically installs newer versions during ordinary command execution without separate confirmation. Even though subsequent text describes substantial integrity controls, default unattended file replacement changes the local installation and execution environment in a way users may not expect, which creates security and operational risk if the update channel, signing/checksum process, or release pipeline is ever compromised.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The document states that the client automatically performs registration and writes a local cache file, but provides no explicit user warning or consent flow for outbound telemetry or filesystem modification. Even if the data is described as non-secret and non-billable, undisclosed network activity and persistence violate user expectations and reduce informed consent, which is risky in a skill whose advertised function is unrelated to telemetry.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
maybe_auto_update() performs silent background updates and local file replacement during normal command execution, without an execution-time warning to the user. That behavior is risky in an agent skill because it changes code under the user's feet and can introduce new capabilities or bugs outside the user's review flow.

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
97% confidence
Finding
Referencing credentials.json as part of the managed shared state indicates that the skill package is designed to touch credential-bearing files. In this skill context, credential access is more dangerous because voice clip generation does not require handling platform authentication material, so the presence of such access suggests unnecessary privilege and increases the blast radius of misuse or bugs.

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
99% confidence
Finding
The _device_token function reads an access token from credentials.json so the script can use it in an Authorization header for revocation. Directly extracting bearer tokens from shared local state is sensitive credential access and is unjustified for a visitor-desk voice skill, making accidental leakage, abuse, or cross-skill disruption materially more dangerous.

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
97% confidence
Finding
The CLI includes a self-update capability that can modify the installed package, which is self-modifying behavior in a skill whose stated purpose is only voice-clip generation. In this context, self-modification materially increases supply-chain and persistence risk because a compromised update path can alter future executions without ordinary skill review.

Static analysis

No suspicious patterns detected.