Back to skill

Security audit

AI Video Restyler

Security checks for vulnerabilities and agentic risk

Overview

The skill appears to be a real video-restyling integration, but it grants broad Beatra account powers and can silently update its own code, so it should be reviewed before installation.

Install only if you trust Beatra with a shared local device token that can authorize more than this one video workflow and with a default-on updater that can replace the skill's own files. Review the authorization page carefully, disable automatic updates if your environment requires change approval, and revoke the Beatra device authorization if you stop using the skill.

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

Warning
Location
scripts/authorize.py:30
Finding
Overprivileged Device Token Permits Operations Unrelated to Video Restyling<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:30-34`; `scripts/mcp_client.py:1463-1482` **Vulnerability Type**: Excessive authorization scope and unrestricted MCP tool dispatch **Risk Level**: Medium ### 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 client also allows the caller to provide an arbitrary 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 Skill functionality is video restyling. Its legitimate requirements include uploading media, discovering compatible video-edit models, initiating video-edit tasks, reading task results, optionally cancelling tasks, and reading relevant billing information. The authorization request nevertheless includes unrelated capabilities for: - Image generation - Music generation - Speech generation - Voice reading and writing - General wallet spending - Broad MCP tool access The local client does not restrict `tool_name` to the tools required by this package. Any local caller able to invoke the script as the user can select an arbitrary MCP tool, with server-side authoriz ...[truncated 1659 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared full-scope token with a package-specific or capability-specific token. 2. Limit requested scopes to those strictly needed for this Skill, such as: - Video editing - User-selected media upload - Video model discovery - Task read and user-requested cancellation - Read-only wallet or ledger access, if required 3. Remove image, music, speech, and voice scopes unless the user explicitly invokes a separate workflow requiring them. 4. Separate read-only billing access from spending authority. Request spending authorization only immediately before a user-approved paid operation where the platform supports incremental authorization. 5. Add a local allowlist for permitted MCP tools. For this Skill, allow only explicitly required operations such as: - `beatra.models.list` - `beatra.assets.upload` - `beatra.videos.edit` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.tasks.cancel` - Required read-only wallet operations - Installation registration, if retained 6. Reject all other tool names before loading or transmitting the bearer credential. 7. Use separate credentials for unrelated Beatra packages instead of allowing every package to inherit the same full account scope. 8. Display the exact requested capabilities on the authorization page so the user can make an informed decision. ]]>

T03 · Remote Payload Retrieval and Execution

Warning
Location
scripts/mcp_client.py:969
Finding
Default Silent Updater Can Replace Executable Skill Files Without Independent Signature Verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:299-330`, `scripts/mcp_client.py:469-490`, `scripts/mcp_client.py:801-925`, `scripts/mcp_client.py:969-1019` **Vulnerability Type**: Mutable remote code delivery through an automatically installed update channel **Risk Level**: Medium ### Vulnerable Code The updater obtains expected checksums from the remotely supplied discovery document: ```python def _release_urls(discovery: dict[str, Any]) -> tuple[str, str]: version = discovery.get("version") archive = discovery.get("archive") manifest = discovery.get("manifest") base_url = discovery.get("base_url") expected_base = PACKAGE_CDN_BASE_TEMPLATE.format(version=version) expected_archive = f"{PACKAGE_SLUG}-skill-{version}.zip" if ( discovery.get("schema_version") != 1 or discovery.get("package") != PACKAGE_SLUG or discovery.get("channel") != PACKAGE_CHANNEL or discovery.get("locale") != PACKAGE_LOCALE or not isinstance(version, str) or archive != expected_archive or manifest != "skill-manifest.json" or base_url != expected_base or not isinstance(discovery.get("archive_sha256"), str) or _SHA256.fullmatch(discovery["archive_sha256"]) is None or not isinstance(discovery.get("manifest_sha256"), str) or _SHA256.fullmatch(discovery["manifest_sha256"]) is None ): raise RuntimeError("Beatra update discovery is invalid") parsed = urllib.parse.urlsplit(expected_base) if ( parsed.scheme != "https" or parsed.hostname != "cdn.beatra.ai" or parsed.username is not None or parsed.password is not None or parsed.query or parsed.fragment ): raise RuntimeError("Beatra update discovery is invalid") return f"{expected_base}/{archive}", f"{expected_base}/{manifest}" ``` Those same remotely supplied values are then used to validate the manifest and archi ...[truncated 6620 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Sign release metadata with an offline-protected publisher key. 2. Embed or securely provision the corresponding public verification key in the reviewed client. 3. Verify the discovery metadata signature before trusting: - Version information - Manifest URL - Archive URL - Manifest checksum - Archive checksum 4. Prefer a mature signed-update design such as The Update Framework, including: - Root, targets, snapshot, and timestamp metadata - Metadata expiry - Rollback and freeze-attack protection - Explicit key rotation - Threshold signatures for high-value release roles 5. Treat SHA-256 checksums as integrity controls only; do not treat them as proof of publisher authenticity. 6. Make executable auto-installation opt-in rather than enabled by default. 7. When an update is available, display the current version, target version, verified signer, and changed executable files before requesting confirmation. 8. Consider allowing silent checks by default while requiring explicit approval before replacing Python scripts or Skill instructions. 9. Record the verified signer identity and release metadata version in local update state for auditability. 10. Continue using the existing redirect, path, archive, ownership, transaction, and rollback protections in addition to signature verification. ]]>
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 (16)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill exposes broad capabilities including shell, network, file read/write, and environment access, yet declares no permissions or prominent trust boundaries. That combination is dangerous because users and host systems cannot make an informed consent decision about a package that can inspect local files, upload data remotely, modify local package files, and access credentials through the bundled client workflow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented purpose is simple video restyling, but the skill also includes unrelated high-risk behaviors such as OAuth authorization, credential storage, arbitrary artifact upload, generic remote tool invocation, telemetry/registration, uninstall cleanup, and self-update with file replacement. This mismatch is dangerous because it hides materially different attack surfaces and can cause users to authorize a media-editing skill that actually performs persistent account, network, and local-system actions beyond the expected workflow.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The authorization scope is far broader than the skill’s stated purpose of video restyling. Requesting generalized generation, artifact, task, and wallet-related access violates least privilege and means compromise or misuse of this skill grants access well beyond video styling operations.

Context-Inappropriate Capability

High
Confidence
93% confidence
Finding
The skill requests task-management permissions like `tasks:read` and `tasks:cancel` without clear justification from the published workflow. Unnecessary operational permissions can let the skill inspect or interfere with unrelated user jobs, increasing cross-skill impact.

Context-Inappropriate Capability

High
Confidence
93% confidence
Finding
The skill requests task-management permissions like `tasks:read` and `tasks:cancel` without clear justification from the published workflow. Unnecessary operational permissions can let the skill inspect or interfere with unrelated user jobs, increasing cross-skill impact.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The skill requests task-management permissions like `tasks:read` and `tasks:cancel` without clear justification from the published workflow. Unnecessary operational permissions can let the skill inspect or interfere with unrelated user jobs, increasing cross-skill impact.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The client embeds a self-update channel and package-discovery mechanism that exceeds the stated purpose of a video-restyling skill. Even though the update path includes checksum and path-validation controls, it still introduces code-fetching and file-replacement behavior that can materially change local execution outside the user's immediate task context.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The code records a local skill inventory and registers installation metadata, including package/version/platform details, despite that behavior not being described by the skill's video-restyling purpose. Undisclosed inventorying and telemetry increase privacy and trust risk because they collect and transmit environment metadata unrelated to the core media transformation function.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The host_platform detection logic fingerprints the execution environment using environment variables and persisted host metadata. For a video-restyling skill, this is not obviously necessary and can be used to profile users or tailor later behavior based on the surrounding agent/runtime.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The skill states that ordinary use triggers silent update checks and may install a newer release without separate confirmation. Auto-updating executable package-owned files creates a supply-chain and integrity risk: even if signatures and checksums are checked, users are still running newly downloaded code without explicit approval at execution time, which materially expands the trust boundary and can change behavior after installation.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The document explicitly describes silent automatic updates that replace installed files by default and without separate confirmation. Even with checksum, manifest, path, rollback, and origin validation controls, unattended self-update that modifies local code can create supply-chain and change-management risk because users may not realize the software is altering itself before normal commands run.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The documentation states that the client will automatically perform a registration call and write a local cache file, but it does not clearly foreground these side effects as user-visible privacy and filesystem changes that occur on first use. Even though the data is described as non-secret and non-billable, silent outbound telemetry and local persistence can violate user expectations, enterprise policy, or regulated-environment requirements if not explicitly disclosed before use.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
maybe_auto_update() performs silent package updates during normal command execution and suppresses exceptions, so installed code can change without user-facing notice at run time. In the context of a creative media skill, silent self-modification is especially risky because users would not reasonably expect the tool to rewrite its own files before or during ordinary use.

Missing User Warnings

Medium
Confidence
96% confidence
Finding
register_installation() sends package slug, version, platform, and installation reference to a remote service as best-effort telemetry without a clear user-facing disclosure in the skill behavior. That creates a privacy issue and expands network data sharing beyond what is needed to restyle a video.

Credential Access

High
Category
Privilege Escalation
Content
scope = _required_string(polled, "scope")
            if set(scope.split()) != set(SCOPE.split()):
                raise RuntimeError("Beatra authorization returned an unsupported scope")
            credential_path = state_dir / "credentials.json"
            _atomic_json(
                credential_path,
                {
Confidence
90% confidence
Finding
This code stores a long-lived bearer access token in a local JSON file, creating a valuable credential target on disk. Even with restrictive POSIX permissions, plaintext token storage increases the risk of token theft from local compromise, backup leakage, or endpoint tooling exposure; this is more dangerous because the token carries overly broad scopes including wallet and account-level capabilities.

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 skill exposes built-in self-update functionality that can replace files in the installed package, which is a form of self-modification. Although the updater has several integrity checks, self-modifying behavior remains dangerous in a skill whose declared purpose is video restyling because it expands trust from current code to future remotely supplied code.

Static analysis

No suspicious patterns detected.