Back to skill

Security audit

wedding-opening-film

Security checks for vulnerabilities and agentic risk

Overview

This wedding-film skill has a real media-generation workflow, but it also uses broad shared account permissions and silent self-updates that users should review before installing.

Install only if you are comfortable giving this Beatra package a shared device credential with more capabilities than wedding-film generation, recurring registration metadata, and default silent self-updates. Disable auto-update before normal use if available, review the OAuth approval page carefully, and avoid supplying sensitive ceremony details unless you are comfortable sending them to Beatra.

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:28
Finding
OAuth Device Token Requests Permissions Beyond the Skill's Functional Requirements<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:28-31` **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" ) ``` ### Technical Analysis The Skill's declared workflow requires image generation, video generation, artifact handling, model and task inspection, and billing-related operations. The authorization scope also grants unrelated capabilities, including: - Music generation - Speech generation - Voice reading and writing - Broad wallet spending - Task cancellation These permissions are not necessary to create three wedding storyboard keyframes and one opening video. The documentation also identifies the resulting credential as a shared, full-scope Device Token in `references/mcp-connection.md:8-10`: ```text They share the one full-scope Device Token stored in `~/.beatra/credentials.json`. ``` This violates least-privilege principles. Because the credential is shared by multiple Beatra Skills, compromise of this Skill or its update channel could expose capabilities and tasks outside this package's intended workflow. ### Attack Path 1. The user runs `scripts/authorize.py`. 2. The authorization request asks the user to approve the complete scope defined in `SCOPE`. 3. Beatra returns a bearer token containing unrelated generation, wallet, voice-management, and task-cancellation permissions. 4. The token is stored in `~/.beatra/credentials.json`. 5. Any malicious replacement client, compromised local process, or attacker who obtains the token can invoke unrelated Beatra operations. 6. The attacker can spend credits on music or speech generation, modify voice resources, or cancel tasks belonging to other workflows that share the credential. ### Impact Assessment Successful abuse cou ...[truncated 460 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the full shared scope with a package-specific least-privilege scope. 2. Retain only permissions demonstrably required by this workflow, such as: - Image generation - Video generation - Required artifact upload/read operations - Model and task reads - Narrow billing or wallet-read access when requested 3. Remove music, speech, voice-write, unrelated voice-read, broad wallet-spend, and task-cancellation permissions unless a documented workflow explicitly requires them. 4. Separate read-only wallet access from billable-generation authorization where the API permits it. 5. Avoid sharing one full-account bearer token across unrelated Skills. Use package-scoped credentials or server-enforced package authorization boundaries. 6. Display the requested capabilities to the user before authorization and explain why each permission is required. 7. Add automated tests that reject authorization scope additions not mapped to declared Skill functionality. ]]>

other

Warning
Location
scripts/authorize.py:341
Finding
Unnecessary Hostname and Agent-Environment Telemetry<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:341-371`, `scripts/authorize.py:469-481`, `scripts/mcp_client.py:1139-1166`, `scripts/mcp_client.py:1354-1398` **Vulnerability Type**: Environment reconnaissance and persistent installation telemetry **Risk Level**: Medium ### 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 hostname is included in the remote device-authorization request: ```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"] = device_name ``` The client also perf ...[truncated 2545 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make hostname and platform telemetry opt-in rather than automatic. 2. Omit `device_name` by default and allow the user to provide a friendly display name explicitly. 3. Default the platform field to `unknown` unless it is operationally required. 4. Avoid persisting the hostname in `~/.beatra/host.json`. 5. Replace the stable installation identifier with a package-scoped or rotating pseudonymous identifier where possible. 6. Do not inject source-platform telemetry into every business call unless the user has consented. 7. Clearly disclose the exact fields, purpose, transmission frequency, retention period, and deletion mechanism before collection. 8. Provide a command or configuration option that disables installation registration and source-attribution telemetry without disabling generation functionality. 9. Minimize server retention and prevent the telemetry from being used for advertising or unrelated profiling. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:515
Finding
Silent Remote Code Replacement Is Enabled by Default<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:515-545`, `scripts/mcp_client.py:931-1019`, `scripts/mcp_client.py:1541-1544` **Vulnerability Type**: Automatic retrieval and installation of remotely controlled executable code **Risk Level**: High ### Vulnerable Code The absence of valid local update state enables automatic updates by default: ```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: ```python else: maybe_auto_update() ``` The updater downloads and installs a newer package without separate confirmation: ```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 ``` ### Technical Analysis Before ordinary authenticated Beatra commands, the client may contact a fixed Beatra discovery endpoint, download a release manifest and archive, and replace package files. This includes replacement of `scripts/mcp_client.py`, which executes in later invocations and has access to the shared bearer credential. The updater contains meaningful defensive controls: - HTTPS-only fixed Beatra endpoints - Redirect rejection - Package, channel, locale, and version validation - Archive and per-file s ...[truncated 2282 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. Update checks may remain optional, but package replacement should require explicit informed user approval. 2. Separate update operations from authenticated business calls so routine generation commands cannot silently alter executable code. 3. Sign release manifests using an offline publisher key and pin the corresponding public key in the audited client. 4. Verify signatures before trusting version numbers, archive hashes, manifests, or replacement files. 5. Define a secure signing-key rotation and revocation process. 6. Use reproducible releases and publish transparency-log entries so users can independently verify package provenance. 7. Display the target version, publisher identity, changelog, and affected files before installation. 8. Preserve the existing archive path, size, checksum, traversal, symlink, ownership, rollback, and collision controls. 9. Consider delegating updates to the host Skill marketplace or package manager rather than implementing self-modifying application code. 10. Ensure update refusal or failure never causes authenticated requests to be replayed, which the current documentation already requires. ]]>
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (26)

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill declares a narrow wedding-film purpose but embeds instructions that require shell execution, network access, local file access, and package modification/update behavior without any explicit permission declaration. This creates hidden capability expansion: a user invoking a content-generation skill may unknowingly grant a path to credential handling, remote calls, and filesystem changes well beyond the expected scope.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented behavior substantially exceeds the stated function of generating wedding storyboard frames and a clip, including OAuth login, persistent credential storage, arbitrary remote MCP invocation, local file upload, telemetry/registration, uninstall/token revocation flows, and self-update. This mismatch is dangerous because it obscures sensitive operations behind an innocuous creative-use description, increasing the chance that operators approve or execute the skill without understanding its true trust and attack surface.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The skill includes bundled-client auto-update and self-modifying package behavior, which is unrelated to wedding-film generation and materially increases supply-chain and integrity risk. Even with signature-verification claims, embedding autonomous update logic in a skill means future code can change after approval, reducing auditability and potentially introducing new behavior without fresh review.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
Automatic software update capability is context-inappropriate for a wedding-opening-film skill because the task domain does not require self-management of executable code. This broadens the attack surface unnecessarily and normalizes execution of mutable code in a low-risk creative workflow, making misuse or compromise more consequential than users would expect.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The manifest presents the skill as a wedding storyboard generator, but the changelog advertises added balance and ledger access that are unrelated to the declared purpose. This capability mismatch is a strong indicator of deceptive scope and could let the skill access financial/account data under an innocuous cover, increasing the chance of unauthorized data exposure or user deception.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
Financial or account-read functionality is context-inappropriate for a wedding opening film skill and has no obvious business need based on the description. In a mismatched context like this, even read-only access is dangerous because it can expose sensitive balances, transaction history, or identifiers while disguising the access as part of a harmless media workflow.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The documentation describes automatic installation registration behavior that is unrelated to the stated wedding-film generation purpose of the skill. Even if framed as non-billable and best-effort, it introduces unnecessary external communication and host metadata collection, which expands the trust boundary and creates a privacy and supply-chain concern in a creative tool context.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The file documents an external installation registration capability that is not justified by the skill's advertised functionality. Collecting package slug, version, platform, and an external installation reference for a wedding-media skill can enable tracking or inventorying deployments without user need, making the behavior risky and contextually suspicious.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The authorization flow requests a very broad OAuth scope set, including images, videos, music, speech, voices, task control, artifact access, and wallet spending, while the skill is described as generating wedding storyboard keyframes and an opening film from user-supplied facts. This violates least-privilege and materially increases blast radius if the credential is misused, stolen, or if the skill behaves unexpectedly.

Context-Inappropriate Capability

Critical
Confidence
95% confidence
Finding
The requested tasks:read and tasks:cancel scopes allow visibility into and interference with task workflows unrelated to this wedding film skill's narrow purpose. Even without direct code misuse shown here, obtaining these permissions expands control over other user operations and increases cross-feature impact from credential compromise.

Context-Inappropriate Capability

High
Confidence
95% confidence
Finding
The requested tasks:read and tasks:cancel scopes allow visibility into and interference with task workflows unrelated to this wedding film skill's narrow purpose. Even without direct code misuse shown here, obtaining these permissions expands control over other user operations and increases cross-feature impact from credential compromise.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The requested tasks:read and tasks:cancel scopes allow visibility into and interference with task workflows unrelated to this wedding film skill's narrow purpose. Even without direct code misuse shown here, obtaining these permissions expands control over other user operations and increases cross-feature impact from credential compromise.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
This file embeds a full remote self-update and installation-management system, including downloading manifests and archives and replacing local package files, behavior unrelated to generating wedding opening films. In the context of a creative skill, this greatly expands attack surface and gives a remote service the ability to change code on disk, turning compromise of the update channel or package authority into arbitrary code execution on the host.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The client exposes generic MCP tool listing and arbitrary tool invocation via CLI rather than restricting itself to wedding-opening-film-specific operations. That makes the package a general remote capability broker: if the backing MCP server offers sensitive tools, the skill can be used to access them far beyond its declared purpose, violating least privilege and making abuse harder for users to notice.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill fingerprints the host environment and records installation telemetry/inventory unrelated to creating wedding film assets. While not immediately code-execution, this increases privacy and surveillance risk, creates unnecessary data collection, and in combination with remote registration can expose user environment details outside the expected scope of a media-generation skill.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
This code performs OAuth device-token revocation against a shared Beatra authorization service during package uninstall. For a wedding-film generation skill, managing and revoking shared device credentials is out of scope and can disrupt other installed skills or broader platform access if the inventory is incomplete, stale, or manipulated.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The script explicitly targets shared files under ~/.beatra, including credentials, host, installation, registrations, and inventory state. A content-generation skill should not delete global platform state, because doing so can break unrelated skills, remove credentials, and cause denial of service across the device.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The function reads an access token from shared credentials.json, giving the skill authorization-management capability unrelated to wedding-film generation. Access to bearer tokens materially increases risk because the token can be used to revoke device authorization or potentially interact with platform APIs if reused elsewhere.

Missing User Warnings

Medium
Confidence
77% confidence
Finding
The skill is designed to process couple-supplied ceremony facts, which can include personal or sensitive information such as names, dates, locations, family details, and relationship history. The manifest provides no privacy warning, retention notice, or handling constraints, creating a risk that sensitive personal data may be collected or transmitted without adequate user awareness or safeguards.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The document explicitly states that the client performs silent, default-enabled update checks and automatically installs newer versions without separate confirmation. Even though it describes integrity checks and rollback protections, background network access and automatic file replacement materially change user state and code execution surface without an explicit opt-in, which creates supply-chain and user-consent risk.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation states that the client automatically performs registration and writes a local cache file, but it does not present this as telemetry-like behavior requiring clear user notice. Silent network transmission plus filesystem writes can violate user expectations, especially in a wedding-content generation skill where users would not reasonably expect background registration activity.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
maybe_auto_update() performs silent best-effort updates during normal command execution and suppresses exceptions, so package files may be modified without clear runtime notice to the user. In a skill that should only transform wedding facts into storyboard output, stealthy code mutation is especially risky because users have little reason to expect installer-like behavior or to scrutinize it.

Credential Access

High
Category
Privilege Escalation
Content
},
  "mcp": {
    "authentication": "device-bearer",
    "credential_file": "~/.beatra/credentials.json",
    "name": "beatra",
    "transport": "streamable-http",
    "url": "https://mcp.beatra.ai/mcp"
Confidence
88% confidence
Finding
The manifest explicitly references a local bearer-credential file, indicating the skill can operate with reusable authenticated access to a remote MCP service. In the context of a wedding media skill—already showing suspicious scope mismatch—this increases the risk that a compromised or deceptive workflow could use stored credentials to access unrelated remote capabilities or sensitive account data.

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
92% confidence
Finding
Referencing credentials.json as part of a deletion set indicates the skill is designed to operate on shared credential material. Even without exfiltration, touching credential storage from an unrelated skill is dangerous because it can destroy or misuse authentication state and violates least-privilege boundaries.

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
97% confidence
Finding
This line accesses shared credentials.json to retrieve an access token, which is credential access by definition. In the context of a wedding-opening-film skill, that access is unnecessary and expands the blast radius from simple media generation to account/device control.

Static analysis

No suspicious patterns detected.