Back to skill

Security audit

Temu Main Image Video

Security checks for vulnerabilities and agentic risk

Overview

The skill performs the advertised image-to-video workflow, but it asks for broad persistent Beatra account authority and silently self-updates executable package files by default.

Review this before installing if you need strict least privilege. Installing connects a Beatra account, stores a local bearer token, uploads selected images to Beatra, sends limited device/package registration metadata, and enables silent package self-updates by default. Consider disabling auto-updates with `python3 scripts/mcp_client.py update --auto off`, and revoke the device from the Beatra Console if you no longer want the shared credential active.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:31
Finding
Authorization Requests Permissions Beyond the Skill's Declared Functionality## Vulnerability Details **File Location**: `scripts/authorize.py:31-35` **Vulnerability Type**: Excessive OAuth authorization scope **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" ) ``` The broad credential is subsequently accepted by the generic tool-call interface in `scripts/mcp_client.py:1462-1480`: ```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 workflow requires product-image upload, image-to-video generation, model discovery, task monitoring, cancellation, and limited billing operations. The authorization scope additionally grants music generation, speech generation, voice creation and reading, general image generation, and broad wallet-spending authority. This violates least privilege. The local client also accepts an arbitrary MCP tool name rather than enforcing a package-specific allowlist. Consequently, any process capable of invoking the bundled client can attempt to use unrelated capabilities covered by the shared bearer credential. The issue does not prove ...[truncated 1264 chars]
Remediation
## Remediation Suggestions 1. Replace the broad scope with the smallest set required for: - artifact upload and read access; - model-card discovery; - image-to-video generation only; - task read and user-requested cancellation; - narrowly scoped wallet balance, ledger, and approved spending operations. 2. Remove music, speech, voice, and unrelated image-generation permissions. 3. Add a local allowlist in `mcp_client.py` and reject every tool not explicitly required by this package. 4. Separate read-only wallet access from paid-generation authorization where the service supports it. 5. Bind authorization grants to the package slug and enforce that binding server-side. 6. Require reauthorization after narrowing the scope so previously issued broad credentials do not remain active.

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Silent Default-On Updates Retrieve and Install Remotely Controlled Executable Code## Vulnerability Details **File Location**: `scripts/mcp_client.py:969-1018` **Vulnerability Type**: Automatic remote payload retrieval and execution **Risk Level**: High ### Vulnerable Code ```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 ...[truncated 3753 chars]
Remediation
## Remediation Suggestions 1. Disable automatic updates by default and require explicit user approval before installing a new version. 2. Display the current version, proposed version, release identity, and files to be replaced before approval. 3. Sign release manifests with an offline or independently protected signing key and pin the corresponding public key in the audited package. 4. Verify signatures independently of TLS and publisher-supplied checksums. 5. Consider a transparency log or reproducible release metadata so unauthorized publication is detectable. 6. Separate update checking from installation: silent checks may be acceptable, but code replacement should require confirmation. 7. Avoid updating immediately before credential-bearing or paid operations. 8. Preserve the existing path, size, checksum, ownership, rollback, and redirect protections, as these remain valuable defense-in-depth controls.

other

Note
Location
scripts/authorize.py:344
Finding
Authorization and Registration Collect Persistent Host and Agent-Environment Telemetry## Vulnerability Details **File Location**: `scripts/authorize.py:344-368` **Vulnerability Type**: Environment reconnaissance and persistent device telemetry **Risk Level**: Low ### Vulnerable Code ```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 sent during authorization in `scripts/authorize.py:447-460`: ```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": PACKAGE_SLUG, } if device_name: form["device_name"] = ...[truncated 2031 chars]
Remediation
## Remediation Suggestions 1. Make hostname transmission opt-in and omit `device_name` by default. 2. Clearly disclose all authorization and registration telemetry before it is sent. 3. Allow users to provide a non-identifying display label instead of the system hostname. 4. Use a rotating or purpose-limited pseudonymous identifier where a stable installation reference is not operationally required. 5. Separate required authentication fields from optional analytics or registration data. 6. Provide a switch to disable installation registration without disabling creative operations. 7. Minimize retention and document the server-side retention, deletion, and correlation policy for these identifiers.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • 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 (7)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill exposes significant capabilities including filesystem access, shell execution, environment access, and network use, yet declares no permissions. That creates a transparency and consent gap: a user expecting a simple image-to-video workflow would not understand that the skill can read/write local state, invoke commands, and reach remote services. In a skill that handles local files and bundled scripts, undeclared capabilities increase the risk of unintended data access or abuse if the package or update path is compromised.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The declared purpose is narrowly framed as converting one Temu image into a short clip, but the skill also performs authentication, persistent credential storage, local file upload, remote tool invocation, registration/telemetry, uninstall/revocation flows, and automatic software updates. This mismatch is dangerous because users may grant trust based on a simple media-editing description while the skill actually establishes a much broader trust boundary and ongoing access to local and remote resources. The hidden operational scope makes social engineering, over-collection, and supply-chain risk materially worse.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill states that the bundled client silently installs newer releases automatically without separate confirmation. Even with signature and integrity checks, silent auto-update in a tool with shell, filesystem, network, and credential-handling capabilities introduces a supply-chain execution path where code changes land on the host without an explicit approval moment. In this context, automatic replacement of package-owned files materially increases the blast radius of any compromise in the update infrastructure or signing process.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The code writes host metadata such as detected platform and device hostname to disk in host.json without any user-facing notice or consent flow. While not an immediate code-execution flaw, it creates an undisclosed local inventory of environmental data that may expose privacy-sensitive context to other local processes or users who can access the state directory.

Missing User Warnings

Low
Confidence
88% confidence
Finding
The skill records a local inventory of installed skills including slug, platform, and resolved install_path in skills.json without explicit warning. This creates a persistent map of local filesystem locations and installed capabilities, which is sensitive environment metadata and may aid profiling or later targeting if exposed.

Missing User Warnings

Medium
Confidence
85% confidence
Finding
The client performs silent automatic self-updates during normal command execution, which modifies installed package files without a contemporaneous user-facing prompt. Although the code includes strong integrity checks and origin restrictions, this still expands the trust boundary: any compromise of the vendor update channel, signing process, or package pipeline would translate into remote code replacement on the host.

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
90% confidence
Finding
This skill contains explicit self-modification capability through its update flow, allowing it to replace its own installed files. Even with checksum validation and path-safety checks, self-updating executable code is inherently sensitive because it creates a remote path to alter local behavior and can become a supply-chain execution vector if the upstream distribution channel is compromised.

Static analysis

No suspicious patterns detected.