Back to skill

Security audit

Resident Event Pack

Security checks for vulnerabilities and agentic risk

Overview

This skill is a disclosed Beatra image-generation workflow, but it asks for and persists broader account authority than the resident-event still task needs.

Install only if you are comfortable granting this package a shared Beatra device token with broad media, wallet, artifact, and task permissions. Consider disabling automatic updates with `python3 scripts/mcp_client.py update --auto off`, and authorize it only for accounts where Beatra credit spending and uploaded reference media are acceptable.

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:33
Finding
Device authorization exceeds the Skill's functional requirements and permits unrestricted MCP tool dispatch<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:33-36`; `scripts/mcp_client.py:1484-1504`; `scripts/mcp_client.py:1519-1524` **Vulnerability Type**: Excessive OAuth scope and missing tool allowlist **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 command dispatcher accepts 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}, ) ``` ```python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name") ``` ### Technical Analysis The declared functionality is the creation of resident-event still images. It legitimately requires image-generation operations, model discovery, relevant artifact access, and task-status reads. However, the authorization request also includes permissions for: - Video generation - Music generation - Speech generation - Reading and writing voice resources - Wallet spending - Task cancellation - General MCP tool access These permissions materially exceed the minimum privileges required for the image-only workflow. The problem is compounded by ...[truncated 1894 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared full-scope authorization with a package-specific, least-privilege scope. For this Skill, authorize only the exact image, model, artifact, task-read, and wallet-read operations required by the documented workflow. 2. Remove unrelated permissions such as `videos:generate`, `music:generate`, `speech:generate`, `voices:write`, and `tasks:cancel` unless a concrete, user-visible feature requires them. 3. Separate wallet inspection from wallet spending. Grant spending permission only immediately before explicitly approved billable work, if the platform supports incremental authorization. 4. Add a strict local allowlist to `_run_command`, for example: - `beatra.models.list` - `beatra.images.generate` - `beatra.images.edit` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.wallet.get` - `beatra.wallet.ledger` - Any narrowly required upload operation 5. Reject all other tool names before opening an MCP session. 6. Require explicit user confirmation for each billable generation and destructive operation, including task cancellation. 7. Avoid sharing one full-scope token among unrelated Skills. Use per-package or capability-bound credentials so compromise of one package cannot exercise another package's privileges. 8. Add automated tests proving that unrelated media, voice-write, wallet-spend, and cancellation tools cannot be invoked through this package. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:978
Finding
Silent default-on updater retrieves and installs remotely mutable executable code without independent signature verification<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:515-522`; `scripts/mcp_client.py:978-1018`; `scripts/mcp_client.py:1545-1547` **Vulnerability Type**: Automatic remote payload retrieval and executable file replacement **Risk Level**: High ### Vulnerable Code Invalid or missing 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 ``` The automatic updater downloads and replaces package files without interactive approval: ```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 ): ...[truncated 4017 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic updates by default. Missing, corrupt, or invalid update state should resolve to `auto_update: false`, not `true`. 2. Notify the user when an update is available and require explicit confirmation before downloading or replacing executable files. 3. Cryptographically sign release manifests using a private signing key kept outside the web/CDN publishing infrastructure. 4. Embed or securely provision a pinned public verification key in the client and reject releases whose signatures cannot be verified. 5. Sign metadata that binds together the package name, channel, locale, version, archive digest, manifest digest, and file list. 6. Consider a threshold-signature or offline-release process so compromise of one web deployment credential cannot authorize executable updates. 7. Preserve the existing checksum, traversal, symlink, ownership, downgrade, transaction, and rollback protections as defense-in-depth. 8. Display the current and target versions and a summary of changed files before installation. 9. Do not replace `SKILL.md` or executable scripts during an ordinary business command. Perform updates only through a dedicated update action. 10. Record update results in an auditable local log that contains no credentials or sensitive user content. 11. Provide a documented, persistent opt-in mechanism and ensure corrupted state fails closed without silently restoring automatic updates. ]]>
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 (21)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill declares itself as a simple event-pack generator, but its documented execution requires shell, filesystem, network, and credential-related capabilities with no explicit permission declaration or user-visible scoping. This creates a broad hidden trust boundary: a user invoking a design skill may unknowingly authorize file access, outbound network calls, persistent state changes, and remote service interaction.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
There is a substantial mismatch between the advertised purpose and the actual documented behavior: beyond generating event graphics, the skill performs authentication flows, stores credentials, uploads files, invokes remote services, registers installations, manages billing, and supports self-update/uninstall logic. This is dangerous because users may trust and run the skill under a narrow mental model while it exercises much broader, security-sensitive functionality.

Context-Inappropriate Capability

Medium
Confidence
92% confidence
Finding
The documentation introduces automatic self-update behavior unrelated to the core event-pack task, including download, installation, replacement, and rollback logic. Even if updates are verified, self-modifying behavior materially increases supply-chain and execution risk because future code can change after initial review, potentially expanding capabilities or introducing malicious behavior.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The manifest presents the skill as a benign image/layout generator, but the changelog explicitly mentions added balance and ledger calls. That mismatch is dangerous because it conceals financially relevant capabilities from users and reviewers, preventing informed consent and making abuse or unauthorized account inspection harder to detect.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
Read-only financial balance and ledger access is unrelated to generating resident event still sets, so its presence strongly suggests overprivileged or hidden functionality. Even without write access, exposing balances and ledger history can leak sensitive financial metadata, support profiling, or facilitate follow-on fraud and social engineering.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The file implements a full OAuth device-authorization flow and persistent credential handling for a skill whose stated purpose is generating resident event stills. That mismatch is a strong indicator of hidden account-linking behavior and expands trust far beyond what users would reasonably expect from this package.

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
The requested OAuth scope includes broad powers such as wallet spending, task control, artifact read/write, voices read/write, and media generation beyond the advertised still-image event-pack use case. If granted, the skill could obtain capabilities to spend funds, access unrelated user assets, and operate across multiple service domains with a single token.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The file is a full network-capable MCP client with credential handling, uploads, telemetry, and package update logic, which is substantially broader than the advertised purpose of generating resident event still sets. In a creative skill context, this expanded capability increases attack surface and grants the package ongoing access to network communication and local state unrelated to the user-facing task.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
The code can download manifests and archives from remote infrastructure and replace installed package files, including via automatic paths, which creates a persistent code modification mechanism inside the skill. Even though it performs integrity checks, self-updating executable code is unusually dangerous for a simple content-generation skill because compromise of the vendor update channel or logic errors would directly change local code without normal reinstallation review.

Context-Inappropriate Capability

Medium
Confidence
89% confidence
Finding
The skill records local inventory and sends installation telemetry that is not needed to transform event names into still-set outputs. In this context, unrelated collection and reporting of installation metadata increases privacy risk and indicates the package performs hidden side activities beyond its stated purpose.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The uninstall script manages and can delete shared Beatra credential/state files in ~/.beatra, which is unrelated to the advertised purpose of generating resident event graphics. Even though this occurs during uninstall and includes safeguards, it still gives the skill authority over shared authentication material and other installed skills’ local state, creating an unexpected trust boundary violation if invoked by an agent or user.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
This code performs network-based OAuth device-token revocation against the Beatra API, behavior that is not justified by the skill’s stated event-pack creation functionality. Even if intended for cleanup, embedding credential-management network actions inside a content-generation skill increases attack surface and allows the skill to affect account/device authorization outside its expected scope.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The document states that the client silently checks for updates and automatically installs newer releases without separate confirmation before normal commands. Even with integrity checks and fixed update sources, silent default-on self-updating is system-modifying behavior that can surprise users, change execution semantics, and increase supply-chain blast radius if the trusted update infrastructure or signing process is ever compromised.

Missing User Warnings

Low
Confidence
84% confidence
Finding
The documentation states that the bundled client sends installation metadata to a remote registration endpoint and writes a local cache file, but it does not give an explicit user-facing warning or consent notice. This creates a transparency and privacy issue because users may unknowingly trigger network transmission and filesystem changes on first use, even if the data is described as non-secret and non-billable.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
maybe_auto_update() silently checks for and applies updates during normal command execution, modifying installation files without a user-facing prompt at that time. For a narrowly scoped creative skill, hidden code changes during routine use undermine user trust and make post-compromise persistence or surprise behavior changes more dangerous.

Missing User Warnings

Low
Confidence
83% confidence
Finding
The registration path sends installation telemetry as a best-effort side effect of session setup without user-facing disclosure in the execution path. While not directly enabling code execution, undisclosed outbound metadata transmission is misaligned with the claimed creative function and increases privacy and trust concerns.

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
90% confidence
Finding
The manifest references a local bearer credential file used to authenticate to a remote MCP service. In the context of a skill whose advertised purpose is unrelated to account or financial data, tying execution to reusable credentials increases the risk of unauthorized service access, credential misuse, or expansion into sensitive API operations if the remote endpoint is overprivileged.

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
78% confidence
Finding
This code persists a bearer access token with very broad privileges to a local JSON file, creating a high-value target on disk. Even though permissions are tightened, compromise of the local user context or accidental backup/log exposure could give an attacker reusable account access spanning unrelated capabilities.

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
The script explicitly enumerates credentials.json among files it may remove from the shared ~/.beatra directory. In context, this is direct handling of shared authentication artifacts, which is sensitive because deleting or replacing such files can disrupt other installed skills and affects device authorization beyond this skill’s advertised purpose.

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
95% confidence
Finding
The _device_token function reads access_token from ~/.beatra/credentials.json, giving the skill access to a shared bearer token. Access to shared tokens is dangerous because a compromised or over-privileged skill can reuse them for unauthorized API actions, and here the access is unnecessary for the skill’s public event-pack purpose.

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 package explicitly exposes self-update functionality that changes its own installed code, which is a self-modification capability inappropriate for the declared purpose of creating resident event still sets. In skill ecosystems, self-modification materially raises the stakes of any supply-chain compromise or server-side abuse because the package can persistently rewrite itself.

Static analysis

No suspicious patterns detected.