Back to skill

Security audit

Job Fair Booth Talks

Security checks for vulnerabilities and agentic risk

Overview

This skill appears to make the promised Beatra booth videos, but it asks for broad account powers and can silently replace its own files, so it should be reviewed before installation.

Install only if you trust Beatra with a persistent device token that can spend credits and access Beatra artifacts and tasks beyond this single booth-video workflow. Before use, consider disabling silent updates with `python3 scripts/mcp_client.py update --auto off`, and treat any request to call unrelated Beatra tools, generate unrelated media, or cancel tasks as requiring explicit user approval.

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:30
Finding
Overprivileged Shared Bearer Token Combined with Unrestricted MCP Tool Dispatch<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:30-34`; `scripts/mcp_client.py:1485-1504` **Vulnerability Type**: Excessive authorization scope and missing local tool allowlist **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}, ) ``` ```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 is designed to upload authorized media, synthesize or clone speech, create image-to-video clips, inspect models, read billing information, and monitor associated tasks. However, authorization requests a shared token with substantially broader permissions, including: - Generic MCP tool access - Image generation - Music generation - Broad artifact read and write access - Wallet spending - Task cancellation Some of these permissions, particularly music generation and generic image generation, are not required for the declared job-fair talking-clip workflow. Task cancellation is only conditionally relevant and shoul ...[truncated 2325 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Issue a package-specific least-privilege token** - Remove `music:generate` and unrelated `images:generate` access. - Limit artifact permissions to artifacts created or explicitly selected for this workflow. - Split task cancellation from ordinary task-read access. - Avoid a generic `mcp:tools` grant when individual tool grants are available. 2. **Add a strict local tool allowlist** Permit only the operations required by the declared workflow, such as: - `beatra.assets.upload` - `beatra.models.list` - `beatra.voices.list` - `beatra.voices.clone` - `beatra.speech.synthesize` - `beatra.videos.animate` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.wallet.get` - `beatra.wallet.ledger` - `beatra.installations.register` Reject every other tool name before initializing a privileged session. 3. **Separate sensitive capabilities** - Require explicit user confirmation immediately before task cancellation. - Use a separate, short-lived spending grant for paid generation. - Keep read-only wallet and task operations on a read-only credential where feasible. 4. **Enforce restrictions server-side** A local allowlist is defense in depth, not a substitute for server-side authorization. The service should bind tokens to the package identity and reject unrelated tool calls even if a modified client submits them. 5. **Audit and log tool identity safely** Record the invoked tool name, package identifier, and request identity without recording bearer tokens or sensitive prompt contents. ]]>

T03 · Remote Payload Retrieval and Execution

Warning
Location
scripts/mcp_client.py:943
Finding
Default Silent Updates Can Replace Executable Skill Files Without Publisher-Signature Verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:515-523`, `scripts/mcp_client.py:943-1019`, `scripts/mcp_client.py:1528-1530` **Vulnerability Type**: Silent remote code replacement through a remotely controlled update channel **Risk Level**: Medium ### Vulnerable Code The update setting defaults to enabled when state is absent or invalid: ```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 ``` Ordinary commands invoke the silent updater before performing their requested operation: ```python else: maybe_auto_update() ``` The updater downloads a remote release and replaces package-owned files: ```python 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( install_root=resolved_root, update_home=update_home, discovery=discovery, manifest=manifest, new_files=new_files, ) return True ``` The update trust checks use hashes supplied by the remote discovery metadata: ```python if _sha256(manifest_content) != discovery["manifest_sha256"]: raise RuntimeError("Beatra update manifest checksum does not match discovery") manifest = _j ...[truncated 3765 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. **Disable automatic installation by default** - Permit automatic update checks, but require explicit user confirmation before replacing executable files. - Clearly show the current version, target version, source, and affected files. 2. **Add cryptographic publisher authentication** - Sign release metadata with an offline or otherwise strongly protected asymmetric signing key. - Embed or securely provision the corresponding public key in the reviewed client. - Verify the signature before trusting any hash, version, manifest, or archive location supplied by discovery. - Define a controlled and auditable key-rotation process. 3. **Use release transparency** - Publish signed release records in an append-only transparency log. - Reject releases that cannot be proven to belong to the expected package and channel. 4. **Avoid silently replacing the active credential client** - Stage the update and require approval before replacing `scripts/mcp_client.py`. - Consider a minimal, separately signed bootstrap updater that does not read user credentials. - Ensure downloaded code is never executed in the same process that validates it. 5. **Preserve the existing archive protections** The current path validation, host pinning, redirect rejection, size limits, ownership checks, transactional replacement, and rollback logic should remain as defense-in-depth controls. 6. **Provide administrative controls** - Support a policy that permanently disables self-update behavior for managed environments. - Make update status observable without transmitting credentials or user content. ]]>
Vulnerability Patterns
  • 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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (13)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares no permissions while instructing use of shell execution, local file inspection/upload, environment-backed authentication, network access, and package-managed updates. This under-disclosure prevents informed consent and weakens platform enforcement, making it easier for the skill to access local data and external services beyond what a user would reasonably expect from a simple video-generation workflow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The published description says the skill creates booth talking clips, but the body also includes OAuth/device authorization, credential storage, authenticated remote tool access, telemetry/registration, uninstall/revocation handling, uploads, and self-updating behavior. That mismatch is dangerous because users may authorize the skill for a narrow creative task without realizing it can manage credentials, transmit local files, and modify its own installation state.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The skill embeds silent automatic update behavior unrelated to the core booth-video task, including download and replacement of package files without separate confirmation. Even with stated verification, self-update expands the trust boundary and creates supply-chain risk: a compromised update channel or signing process could change local behavior after installation without a fresh review or user approval.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The authorization helper requests a very broad OAuth scope set far beyond the stated purpose of turning stills and role notes into short booth talking clips. Unnecessary privileges such as wallet spending, voice management, music generation, and task control violate least privilege and would let a compromised or misused skill access or spend resources unrelated to its workflow.

Context-Inappropriate Capability

Critical
Confidence
95% confidence
Finding
Requesting tasks:read and tasks:cancel grants visibility and control over task state beyond what is justified by the advertised booth-clip use case. These permissions could let the skill inspect unrelated workloads or interfere with other operations under the same account.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
Requesting tasks:read and tasks:cancel grants visibility and control over task state beyond what is justified by the advertised booth-clip use case. These permissions could let the skill inspect unrelated workloads or interfere with other operations under the same account.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
Requesting tasks:read and tasks:cancel grants visibility and control over task state beyond what is justified by the advertised booth-clip use case. These permissions could let the skill inspect unrelated workloads or interfere with other operations under the same account.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
Requesting tasks:read and tasks:cancel grants visibility and control over task state beyond what is justified by the advertised booth-clip use case. These permissions could let the skill inspect unrelated workloads or interfere with other operations under the same account.

Description-Behavior Mismatch

High
Confidence
90% confidence
Finding
The client contains a full self-update subsystem that downloads manifests and archives, validates them, and replaces installed package files on disk. Although there are several integrity checks, this materially exceeds the stated booth-clip generation purpose and creates a software supply-chain modification path inside a content-generation skill, increasing the blast radius if the update channel, signing assumptions, or package publisher are compromised.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The code fingerprints the host environment and sends installation telemetry such as platform and external installation references during normal operation. That behavior is unrelated to generating job-fair booth clips and expands data collection beyond user expectations, creating unnecessary privacy and inventory-leconnaissance risk if the backend or telemetry path is abused.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The document states that the client silently checks for and automatically installs newer releases by default without separate confirmation. Even though the text describes integrity protections for the update source and package contents, default silent modification of installed software materially affects user system state and trust boundaries, and the documentation does not prominently warn users about that behavior or its security implications.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
maybe_auto_update() performs best-effort silent updates during ordinary command execution, allowing installed package bytes to change without a contemporaneous user-facing warning. Even with checksum and manifest validation, silent execution-time mutation is risky in a skill context because it reduces user awareness and can turn a backend or release-process compromise into automatic code deployment.

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
92% confidence
Finding
The CLI exposes a self-update function that can replace files in the installed package, i.e. operational self-modification. In a recruiting media skill, self-modifying behavior is not necessary for the advertised task and creates a high-value persistence and supply-chain abuse surface if the update mechanism or publisher trust is compromised.

Static analysis

No suspicious patterns detected.