Back to skill

Security audit

CS Macro Card Pack

Security checks for vulnerabilities and agentic risk

Overview

The skill’s card-generation workflow is mostly coherent, but it asks for broad account permissions and silently self-updates executable files in ways users should review carefully.

Install only if you are comfortable giving this Beatra package a shared bearer credential with broad paid-media and account capabilities, allowing default silent package updates, and sending limited device/install telemetry. Disable automatic updates with `python3 scripts/mcp_client.py update --auto off` if you need manual control, avoid uploading sensitive reference files, and revoke the Beatra device authorization from the console when you no longer use 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
  • 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 (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:30
Finding
Device authorization requests permissions beyond the Skill's declared image-card functionality<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:30-33` **Vulnerability Type**: Excessive OAuth device-token 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 purpose is to create still image cards from user-provided customer-service scripts. Its legitimate operations include image generation and editing, model and task queries, optional reference-image upload, and limited billing queries. The requested device-token scope additionally permits video, music, speech, and voice operations, general artifact access, task cancellation, and wallet spending. These unrelated permissions violate the principle of least privilege. Although the broad authorization is mentioned in `references/installation-and-auth.md`, disclosure alone does not make the additional privileges necessary. The bearer token is shared through `~/.beatra/credentials.json`. Any package component or same-user process that obtains this token consequently receives all authorized capabilities rather than only those required by this Skill. ### Attack Path 1. The user runs `scripts/authorize.py` to activate the image-card Skill. 2. The helper requests the complete scope defined in `SCOPE`. 3. After approval, Beatra returns a bearer token containing the broad authorization. 4. The token is saved in `~/.beatra/credentials.json`. 5. Compromised package code, a malicious future update, or another same-user process reads the token. 6. The token is used to invoke unrelated paid media operations, access artifacts or tasks, spend credits, or cancel tasks. ### Impact Assessment Successful abuse may permit: - generation of unrelated video, music, speech, and voice content; - wallet-credit spending outside the image-card workflow; - read ...[truncated 388 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared full-scope token with a package-specific token restricted to: - required image generation and editing operations; - narrowly scoped model and task reads; - explicit reference-asset upload; - only the billing reads needed by the documented workflow. 2. Remove video, music, speech, voice-write, broad artifact access, task cancellation, and wallet-spend scopes unless a concrete Skill feature requires each permission. 3. Separate read-only and billable permissions where the service supports capability-specific authorization. 4. Present the exact requested permissions before approval and require fresh consent when a new capability is added. 5. Add server-side enforcement binding the credential to the package identity and approved tool allowlist. 6. Rotate existing broad credentials after introducing reduced-scope authorization. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Default silent updater retrieves and installs remotely mutable executable code without independent signature verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:969-1019` **Related Locations**: `scripts/mcp_client.py:31-32`, `scripts/mcp_client.py:469-492`, `scripts/mcp_client.py:801-932`, `SKILL.md:169-183` **Vulnerability Type**: Silent remote payload retrieval and package-file replacement **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_fi ...[truncated 3131 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. Keep update checks manual or notify the user and require explicit confirmation before changing files. 2. Sign release metadata and payloads with an offline-controlled signing key. 3. Embed or securely pin the corresponding verification public key in the reviewed package so trust does not depend entirely on the discovery/CDN infrastructure. 4. Bind signatures to the package name, channel, version, complete file manifest, and archive digest. 5. Preserve downgrade prevention and the existing path, size, ownership, rollback, and recovery protections. 6. Display the current version, target version, changed files, and source before installation. 7. Consider separating update checking from business commands so a routine paid or authenticated operation cannot silently mutate executable code. 8. Record an auditable local update history and provide a supported rollback command. ]]>

other

Warning
Location
scripts/authorize.py:361
Finding
Authorization and business calls transmit unnecessary hostname and persistent environment telemetry<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:361-374` **Related Locations**: `scripts/authorize.py:438-457`, `scripts/mcp_client.py:1140-1164`, `scripts/mcp_client.py:1215-1228`, `scripts/mcp_client.py:1367-1385` **Vulnerability Type**: Unnecessary host identification and persistent installation telemetry **Risk Level**: Medium ### Vulnerable Code ```python 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 value is included in the remote 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 status, created = post_form(DEVICE_AUTHORIZATION_URL, form) ``` Subsequent business calls also receive source attribution: ```python if method == "tools/call": arguments = params.get("arguments") if isinstance(arguments, dict): arguments.setdefault("source_package_slug", PACKAGE_SLUG) arguments.setdefault("source_platform", host_platform()) ``` ### Technical Analysis The authorization flow reads the machine hostname and sends it to `api.beatra.ai` as `device_name`. It also derives the hosting agent from process-environment signatures and transmits the platform, package slug, package version, and a stable external installation reference. The code does not enumerate IP addresses, user accounts, processes, SSH keys, or arbitrary environment-variable values. Consequently, this is limited environment identification rather than broad ...[truncated 1519 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not collect or transmit the hostname by default. 2. If a recognizable device label is needed, ask the user to provide one explicitly or use a generic randomized label. 3. Make installation and source telemetry opt-in and ensure disabling it does not block core image-generation operations. 4. Minimize transmitted fields to those required for authentication and protocol compatibility. 5. Clearly disclose every collected field, its purpose, retention period, and correlation behavior before authorization. 6. Provide controls to inspect, reset, or delete the stable installation identifier. 7. Avoid attaching source telemetry to every business request unless it is operationally necessary. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mcp_client.py:222
Finding
Server-selected upload URL accepts any HTTPS hostname<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:222-261` **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 upload workflow safely restricts local input to a user-selected regular file, applies ...[truncated 1887 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict upload destinations to an explicit allowlist of documented Beatra-controlled storage domains. 2. Validate the exact scheme, normalized hostname, port, and path prefix; reject unexpected ports and lookalike subdomains. 3. Alternatively, require a cryptographically signed upload policy binding: - destination hostname and path; - HTTP method; - content type and length; - artifact or request identifier; - expiration time. 4. Show the destination domain to the user before transferring sensitive reference media. 5. Strip unnecessary image metadata when compatible with the user's requirements, or offer an explicit metadata-removal option. 6. Continue rejecting redirects and preserving the existing regular-file, size, MIME, and file-stability checks. ]]>
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 (19)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares itself as a simple macro-card generation workflow, yet it instructs the agent to use a bundled Python client with shell, file, environment, and network capabilities. That creates a materially larger trust boundary than the manifest suggests, enabling local file access, network communication, and system changes without explicit permission disclosure to the user.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documented behavior substantially exceeds the stated purpose: beyond generating macro card graphics, it performs authentication flows, persistent credential storage, arbitrary remote MCP tool calls, file upload, telemetry/registration, uninstall logic, and auto-update operations. This mismatch can mislead users and reviewers, causing them to approve a skill under false assumptions about what code and data access it will exercise.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The skill embeds self-updating software behavior unrelated to its business purpose, including remote discovery, download, verification, replacement, rollback, and recovery. Even if intended as maintenance, self-update introduces a software supply-chain and system-modification path inside a content-generation skill, increasing the consequences of compromise or misconfiguration.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The manifest presents a narrowly scoped graphics skill, but the body documents automatic remote update checks and package replacement. This hidden system-modifying capability weakens user consent and security review because the skill can change local package-owned files over time without being understood as installer/updater software.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The requested OAuth scope bundle is far broader than needed for a skill described as turning customer-service macros into still card sets. It includes unrelated capabilities such as videos, music, speech, voice management, task control, and artifact access, creating a substantial over-privilege condition if the token is later misused or the skill is compromised.

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
Requesting wallet:spend plus broad multimodal generation privileges is especially dangerous because it enables direct financial impact and access to unrelated resource-consuming capabilities with a single credential. In the context of a CS macro card skill, these permissions are unjustified and materially expand blast radius from simple card generation to account spending and cross-modal abuse.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The script collects and persists host platform, device hostname, installation path, and skill inventory data that exceed the narrow needs of generating CS macro cards. While this appears operational rather than overtly malicious, it increases privacy and fingerprinting exposure and creates unnecessary local telemetry about the user's environment.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The file implements a broad remote-control client far beyond the declared macro-card purpose: self-update, generic MCP session establishment, arbitrary remote tool calls, uploads, and package replacement on disk. In a narrowly scoped content-generation skill, this materially increases attack surface and enables remote code/content changes unrelated to the advertised functionality, making compromise or abuse of the backend far more dangerous.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The code fingerprints the execution environment by inspecting agent-specific environment variables and persisted host metadata, then attaches that platform label to outbound business calls. While not highly sensitive by itself, this creates unnecessary device/environment telemetry for a macro-card skill and can aid tracking, profiling, or policy differentiation without clear user need.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The code persistently records installation telemetry and a local inventory of installed skills unrelated to generating macro cards, and attempts remote installation registration. This expands data collection and persistence beyond user expectations for the advertised function, creating privacy and governance risk if the local state or backend is abused.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The CLI exposes generic remote tool invocation via 'call' and tool enumeration via 'tools', allowing arbitrary backend capabilities to be exercised through this package rather than only macro-card generation. This breaks least privilege for the skill context and turns a themed content skill into a general-purpose remote operations client if credentials are present.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
This uninstall script can revoke a shared Beatra device credential and remove shared state under ~/.beatra, actions that affect more than this single skill package. Even if framed as cleanup, that scope exceeds the narrowly advertised macro-card functionality and creates a cross-skill denial-of-service risk if invoked unexpectedly or in the wrong context.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The code performs a network POST to revoke an authorization token, giving this skill package remote account/session management capability unrelated to generating macro-card assets. That broad control surface is dangerous because compromise, misuse, or accidental execution can invalidate the user's shared device authorization.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The script explicitly enumerates and later deletes shared state files including credentials, installation, host, skills, and registrations in ~/.beatra. For a skill whose purpose is customer-service macro card generation, access to and deletion of global shared state is unnecessary and increases the blast radius to other installed skills.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Automatic installation updates occur without separate confirmation, which is unsafe for a skill that can modify local files and contact remote infrastructure. Silent updates reduce user control and create a path for unexpected code changes, making exploitation more damaging if the update channel or package integrity process is ever bypassed.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The document describes a client that silently checks for updates and automatically installs them before normal commands without separate confirmation. Even with strong integrity controls, unattended code replacement changes the local installation and execution environment in a way users may not expect, which increases supply-chain and operational risk if the update infrastructure, signing/checksum process, or package channel is ever compromised or misconfigured.

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
84% confidence
Finding
Referencing credentials.json as part of the set of files to remove indicates this skill is designed to handle shared credential material. Even without exfiltration, touching credential storage from a content-generation skill violates least privilege and can break authentication for other components on the device.

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
92% confidence
Finding
The _device_token function reads the access token from credentials.json and uses it for remote revocation. Reading live bearer tokens inside a non-platform skill materially increases credential exposure risk because any bug, logging issue, or future code change could leak or misuse the token, and the current code already uses it to alter account state remotely.

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
Self-update in a skill runtime is dangerous because it allows the package to replace its own on-disk code after fetching remote manifests and archives, which is far beyond the expected behavior of a macro-card generator. Even with checksum validation and path-safety checks, compromise of the update channel or publishing workflow could silently alter the skill's behavior and expand post-install capabilities.

Static analysis

No suspicious patterns detected.