Back to skill

Security audit

amazon-main-image-motion

Security checks for vulnerabilities and agentic risk

Overview

This skill performs a real Beatra image-to-video workflow, but it also requests broad account privileges and silently updates local code by default.

Install only if you trust Beatra with a shared, broad Device Token and potential billable account actions. Review the requested scopes, consider disabling automatic updates with the documented update --auto off command, and avoid using this in sensitive or managed environments unless broad Beatra credential storage, installation registration, selected-file upload, and self-updating package behavior are acceptable.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:34
Finding
Overbroad Device Token Scope Combined with Unrestricted Tool Dispatch<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37`; `scripts/mcp_client.py:1463-1481` **Vulnerability Type**: Excessive authorization scope and missing 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}, ) ``` ### Technical Analysis The Skill's declared purpose is to upload one product image and generate one image-to-video result. Its authorization request nevertheless includes unrelated capabilities for image generation, music generation, speech generation, voice reading and writing, wallet spending, artifact access, and task cancellation. The client compounds this excessive scope by forwarding any command-line `tool_name` to the remote MCP endpoint. It does not enforce a package-specific allowlist. Consequently, the effective authorization boundary is determined entirely by the broad bearer token and server-side controls rather than by the functionality declared by this Skill. The credential is shared through `~/.beatra/credentials.json`, increasing the consequences of token comprom ...[truncated 1297 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Request a package-specific token containing only the scopes required for: - Model-card discovery. - Product-image upload. - Image-to-video generation. - Task status reads. - User-requested task cancellation. - Read-only wallet operations only when those features are used. 2. Remove unrelated image, music, speech, and voice permissions. 3. Separate read-only wallet access from spending authorization where the service supports it. 4. Add a strict local allowlist in `_run_command`, for example: - `beatra.models.list` - `beatra.assets.upload` - `beatra.videos.animate` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.tasks.cancel` - `beatra.wallet.get` - `beatra.wallet.ledger` 5. Reject all unrecognized tool names before creating the MCP request. 6. Use separate credentials per package or per capability instead of one shared full-scope token. 7. Add automated tests proving that unrelated tools cannot be called through this package. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mcp_client.py:231
Finding
Server-Supplied Upload URL Is Not Restricted to an Approved Host<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:231-262` **Vulnerability Type**: Insufficient destination validation for local-file uploads **Risk Level**: Medium ### Vulnerable Code ```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} ``` ### Technical Analysis The client receives upload instructions from the MCP service and checks that the URL uses ...[truncated 1582 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Maintain an explicit allowlist of Beatra-controlled upload hosts and documented cloud-storage endpoints. 2. Validate normalized hostnames exactly; do not use unsafe suffix checks that could accept domains such as `approved.example.attacker.test`. 3. If upload hosts must be dynamic, require a cryptographically signed upload grant binding: - Full URL and hostname. - HTTP method. - MIME type. - Byte length. - Artifact identifier. - Expiration time. 4. Verify the grant signature using a pinned publisher or service key before transmitting file contents. 5. Reject unexpected ports, query formats, and headers unless specifically required by the upload protocol. 6. Document the authorized upload domains so users and administrators can enforce network egress policies. 7. Add tests confirming that attacker-controlled HTTPS hosts and deceptive subdomains are rejected. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Silent Remote Code Updates Rely on Publisher-Controlled Checksums Without Independent Signature Verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:969-1014`; supporting configuration at `scripts/mcp_client.py:31-32` and invocation at `scripts/mcp_client.py:1541-1544` **Vulnerability Type**: Automatic remote payload retrieval and executable replacement **Risk Level**: High ### Vulnerable Code ```python PACKAGE_DISCOVERY_URL = "https://beatra.ai/skills/amazon-main-image-motion/channels/clawhub/install.json" PACKAGE_CDN_BASE_TEMPLATE = "https://cdn.beatra.ai/agent-packages/amazon-main-image-motion/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_baselin ...[truncated 2978 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Sign discovery metadata, manifests, and release archives with an offline-controlled publisher key. 2. Embed or securely provision the trusted public key independently of the update server. 3. Verify signatures before trusting version numbers, URLs, hashes, manifests, or archive contents. 4. Use a framework providing rollback protection and key rotation, such as a design based on The Update Framework. 5. Require explicit user confirmation before replacing executable files, or make automatic updates opt-in rather than enabled by default. 6. Display the target version and verified signer identity before installation. 7. Preserve the existing checksum, path-confinement, archive-limit, ownership, backup, and rollback controls as defense in depth. 8. Record a local update audit log containing the previous version, new version, verified signer, and release digest without recording credentials. 9. Ensure update failures are visible through diagnostics rather than being entirely suppressed, while still preventing failures from causing duplicate paid requests. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (15)

Lp3

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding
The skill exposes materially sensitive capabilities (environment access, file read/write, network, and shell) without declaring permissions or warning the user. That creates a transparency and consent failure: a host or user may treat the skill as low-risk image animation guidance while it can actually execute local commands, access files, and communicate over the network.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documented purpose is narrow, but the actual behavior includes OAuth login, credential storage, arbitrary remote tool invocation, uploads, telemetry/registration, uninstall cleanup, and automatic package management. This mismatch is dangerous because users may consent to a simple media task without realizing they are authorizing broad local and remote operations, including credential handling and code-adjacent execution paths.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The authorization scope is far broader than the skill’s stated purpose of turning a single approved image into a short clip. Requesting wallet spending, music/speech/voice generation, artifact and task access, and broad write capabilities violates least privilege and would let a compromised or misused skill perform unrelated paid actions or access unrelated user data.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The code collects host platform and device hostname metadata and persists it in host.json even though that is not necessary for the advertised image-to-video conversion behavior. This creates avoidable device fingerprinting and privacy exposure, especially when paired with authorization state and installation records.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill records a local inventory of installed skills and paths in ~/.beatra/skills.json, which exceeds the stated purpose of media conversion. Persisting install paths and package history creates unnecessary local surveillance/fingerprinting data that could reveal user tooling, filesystem layout, and usage patterns.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The client embeds package discovery, update, CDN, registration, and telemetry functionality that is materially broader than the declared purpose of generating a short product motion clip from one image. In a creative skill context, this unnecessary control plane increases attack surface and trust requirements, especially because it enables remote package lifecycle operations unrelated to the user task.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
This code downloads package metadata and archives from remote infrastructure and then replaces files under the local installation root, making the skill self-modifying. Even with integrity checks, a remote compromise of the vendor update channel or signing process would let an unrelated image-animation skill rewrite its own code on the host, which is a high-risk capability for this context.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill persistently records local skill inventory and installation telemetry, including install path and platform, despite this being unrelated to producing motion clips. That creates avoidable privacy and reconnaissance risk by maintaining extra local metadata and transmitting installation information to a backend service.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill states that its bundled client can silently install newer releases automatically without separate confirmation. Even if updates are fetched from official paths and verified, silent self-update materially changes the local code and trust boundary after initial approval, which can introduce supply-chain risk or unexpected behavior without contemporaneous user consent.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The document explicitly states that the client silently checks for updates and installs newer releases automatically without separate confirmation. Even with integrity checks and fixed update sources, automatic code replacement changes the local installation and can introduce unexpected behavior or supply-chain risk without an explicit user approval step at update time.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The documentation states that the client automatically performs an outbound installation registration call and writes a local cache file on first use, but it does not describe an explicit user-facing warning, consent flow, or opt-out. Even though the transmitted fields are described as non-secret, sending package, version, platform, and installation reference data without clear disclosure can create privacy, compliance, and trust risks, especially in enterprise or restricted environments.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
Host configuration is written silently as a best-effort side effect of authorization, without meaningful user notice or consent. Undisclosed persistence of environment metadata is a security and privacy issue because users cannot make an informed decision about what the skill stores locally.

Missing User Warnings

Medium
Confidence
86% confidence
Finding
The code silently records a local installation inventory, including slug, platform, and install path, without user-facing disclosure. Even if intended for uninstall coordination, hidden persistence of this data is unnecessary for the advertised function and weakens user trust and privacy.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The code performs silent automatic updates during normal command execution via maybe_auto_update(), changing installed package bytes without a user-facing prompt at the time of modification. For a narrowly scoped creative tool, this weakens user control and can turn any backend or supply-chain compromise into an opportunistic local code change.

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 presence of a built-in self-update command confirms that this skill can intentionally modify its own installed code, a powerful capability unrelated to its advertised image-to-video purpose. In this context, self-modification meaningfully increases supply-chain and post-installation risk because the package can evolve on-host outside normal user expectations.

Static analysis

No suspicious patterns detected.