Back to skill

Security audit

Music Lyric Card Set

Security checks for vulnerabilities and agentic risk

Overview

This lyric-card skill is mostly coherent with Beatra image generation, but it requests broad account permissions and can silently update its own code, so it needs review before installation.

Install only if you are comfortable granting this Beatra package a persistent shared account token with broad media, task, artifact, and wallet authority. Consider disabling automatic updates with the documented update --auto off command, and avoid uploading local files unless they are intended to be sent 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 (2)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:34
Finding
Image-only Skill obtains an excessively broad shared bearer credential<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37` **Vulnerability Type**: Excessive OAuth scopes and missing client-side tool restrictions **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 requested scope is passed directly into the Device Authorization request at `scripts/authorize.py:449-459`: ```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, } ``` The generic client also permits an arbitrary tool name at `scripts/mcp_client.py:1459-1481`: ```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 function of this Skill is to produce lyric-card still images. Its legitimate operations include model lookup, image generation and editing, optional artifact upload, task status management, and limited wallet inspection. The requested bearer credential addition ...[truncated 2378 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared full-scope credential with a package-specific, least-privilege credential. 2. Restrict authorization to the exact operations required by this Skill, such as: - Model metadata lookup for image generation. - Image generation and image editing. - Explicitly approved artifact upload. - Task read and narrowly scoped cancellation. - Read-only wallet balance and ledger access. 3. Remove `videos:generate`, `music:generate`, `speech:generate`, and `voices:write` from this package’s authorization request. 4. Replace generic `wallet:spend` with a capability limited to approved image operations, if supported by the service. 5. Add a client-side allowlist for MCP tools. Reject any tool name not required by the documented workflow. 6. Bind server-side permissions to the package identity and validate that the requested tool is permitted for `music-lyric-set`. 7. Avoid sharing one broad bearer credential among unrelated Skills. Use independently revocable credentials with separate audit trails. 8. Add automated tests asserting that unrelated video, music, speech, and voice tools cannot be called using this Skill’s credential. ]]>

T03 · Remote Payload Retrieval and Execution

Warning
Location
scripts/mcp_client.py:969
Finding
Default silent updater retrieves and replaces executable Skill code without an independent release signature<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:969-1017` **Vulnerability Type**: Automatic remote payload retrieval and executable file replacement **Risk Level**: Medium ### 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_update( install_root=resolved_root, ...[truncated 4046 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. Ordinary commands should only check for updates or notify the user. 2. Require explicit user approval before downloading and replacing executable package files. 3. Sign release metadata with an offline or otherwise independently protected signing key. 4. Embed the corresponding public key or a narrowly scoped trust root in the reviewed client and verify signatures before accepting version or hash metadata. 5. Implement secure key rotation and revocation, rollback protection, and signed expiration metadata. 6. Use separate infrastructure or credentials for metadata signing and CDN publication so one compromised service cannot authorize a malicious release. 7. Display the target version and verified signer identity before installation. 8. Consider requiring a restart or a new Agent session after an update rather than silently continuing from a process that modified its own package. 9. Preserve the existing archive traversal, size, ownership, rollback, and redirect protections; these are useful defense-in-depth measures but should supplement, not replace, authenticated release signing. 10. Record update events in a user-visible local audit log without including credentials or sensitive prompts. ]]>
Vulnerability Patterns
  • 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
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (17)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares no permissions, yet its instructions clearly require shell execution, local file access, network access, and persistent state changes via the bundled client. That mismatch is dangerous because users and the host may authorize a seemingly narrow lyric-card skill without understanding it can read/write files, reach remote services, and modify the local installation through updates.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The skill's stated purpose is limited to generating lyric cards, but the embedded behavior includes authentication flows, credential persistence, arbitrary MCP tool access, uploads, telemetry/registration, uninstall actions, and self-updating package replacement. This broad hidden behavior expands the trust boundary far beyond the advertised task, creating risk of credential exposure, unexpected data exfiltration, and supply-chain compromise if the updater or remote service is abused.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The documentation describes automatic external registration on first use that sends package slug, version, platform, and a stable external installation reference, even though the skill's stated purpose is lyric-card generation. This creates telemetry-style data collection and network behavior outside the user-expected scope, which is dangerous because it introduces undisclosed metadata exfiltration and persistent installation tracking unrelated to the core creative function.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
Collecting and caching platform information plus a stable installation reference is not justified by the described lyric-card generation capability and enables device or environment fingerprinting. In this skill context, the mismatch between benign media-generation functionality and installation-level metadata collection makes the behavior more suspicious and raises privacy and trust concerns, especially because it occurs automatically on use.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill requests a very broad OAuth scope set, including images, videos, music, speech, voices, task controls, artifact access, and wallet spending, while the advertised purpose is only creating still lyric card sets. This violates least privilege and means a compromise, misuse, or even normal operation of the skill could access or spend resources far beyond what users would reasonably expect.

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
The authorization flow asks for voice, speech, music, and video generation rights even though the skill description is limited to four-to-eight still lyric cards. These extra capabilities expand the blast radius of any misuse and can lead to unexpected content generation, extra cost, and access to unrelated media systems.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The authorization flow asks for voice, speech, music, and video generation rights even though the skill description is limited to four-to-eight still lyric cards. These extra capabilities expand the blast radius of any misuse and can lead to unexpected content generation, extra cost, and access to unrelated media systems.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
The file implements a broad network-capable MCP client with credential handling, upload support, telemetry, and package update logic, none of which are necessary for a lyric-card generation skill. In this context, the mismatch is dangerous because it grants the skill a large, unjustified capability surface for external communication and system modification, increasing the risk of data exfiltration, remote tasking, or later abuse if the backend or package channel is compromised.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The skill writes a local skill inventory and sends installation registration telemetry unrelated to converting lyrics into still cards. In this context, collecting and transmitting package/version/platform/install-path metadata is unjustified and creates privacy and tracking risk, especially because it happens opportunistically during normal operations rather than as a clearly consented setup step.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The skill silently checks for updates, downloads remote archives, validates them, and rewrites its own installed files. Even with several integrity checks present, self-modifying behavior is high risk for a lyric-card tool because it expands trust to remote infrastructure and enables code changes outside normal package-management and review workflows.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The code fingerprints the execution environment by inspecting environment variables and host metadata to derive the agent platform. For a lyric-card generation skill, this is unnecessary contextual collection and increases privacy risk while also enabling backend-side profiling or differential behavior based on the host agent.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The uninstall script can revoke a shared Beatra device token and remove global state from ~/.beatra, which affects all skills on the device rather than only this lyric-card skill. Even though the code tries to be conservative and only revoke when it believes no other skills remain, this is still cross-skill credential and state management that exceeds the narrow lyric-card functionality described by the skill and creates unnecessary blast radius if the inventory is wrong or manipulated.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The code reads the global skills inventory and makes security decisions based on the presence or absence of other installed skills, giving this skill visibility into cross-skill state it does not need for lyric-card generation. That broad awareness increases privacy and integrity risk because a compromised or tampered inventory could influence whether shared credentials are retained or revoked, and it violates least privilege for a content-generation skill.

Credential Access

High
Category
Privilege Escalation
Content
def _credentials(state_dir: Path) -> tuple[str, str]:
    state_dir = state_dir.expanduser()
    path = state_dir / "credentials.json"
    try:
        value = json.loads(_read_private_credentials(state_dir, path))
        mcp_url = value["mcp_url"]
Confidence
84% confidence
Finding
The code reads bearer credentials from ~/.beatra/credentials.json and uses them to authenticate outbound MCP requests. Although accessing credentials is necessary for its network client, in the context of a lyric-card skill this is over-privileged behavior: a compromised or repurposed skill can use those credentials to act on behalf of the user against remote services.

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 the files this script may delete indicates the skill is handling shared authentication material stored outside its own package scope. In the context of a lyric-card skill, touching credential storage is unjustified and dangerous because any bug, path confusion, or abuse of this uninstall flow could disrupt authentication for other skills or expose token-handling logic where it is not needed.

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
98% confidence
Finding
The _device_token function reads an access token from ~/.beatra/credentials.json and uses it for revocation, which is direct credential access by a skill whose advertised purpose is only lyric-card generation. Access to bearer tokens is highly sensitive; if this code path were repurposed, logged, or modified, it could enable misuse of shared authorization beyond this skill's own scope.

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 exposed self-update command confirms that this package can modify its own installed code on disk. For a creative lyric-card skill, self-modification is especially dangerous because it allows post-install behavior changes via remote content, undermining static review and making later malicious code introduction harder for users to detect.

Static analysis

No suspicious patterns detected.