Back to skill

Security audit

Policy Digest Pages

Security checks for vulnerabilities and agentic risk

Overview

This skill is disclosed as a Beatra image-generation workflow, but it uses a broad shared account token and silently self-updates package code by default.

Install only if you are comfortable granting Beatra a shared device token with permissions beyond still-image generation and allowing this package to update itself automatically. Consider disabling automatic updates with the documented update --auto off command and reviewing the Beatra approval scope and account billing implications before use.

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)

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:970
Finding
Silent Automatic Retrieval and Installation of Remotely Controlled Executable Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:970-1019`, `scripts/mcp_client.py:1529-1532`; documented in `SKILL.md:139-151` and `references/automatic-updates-and-safety.md:3-7` **Vulnerability Type**: Remote payload retrieval and execution **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_files = download_update(discovery, get_bytes= ...[truncated 3961 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Default automatic installation to disabled. Permit silent update checks, but require explicit informed approval before replacing files. 2. Display the current version, proposed version, release notes, source, and affected files before installation. 3. Sign discovery metadata and release manifests with an offline or separately protected signing key. 4. Embed or securely provision a pinned public verification key in the reviewed package. 5. Verify signatures before trusting version numbers, URLs, or SHA-256 values. Retain hashes for integrity validation after signature verification. 6. Consider a signed metadata framework with rollback and freeze-attack protections, such as TUF-style root, timestamp, snapshot, and targets metadata. 7. Require an explicit command such as `update --install <version>` for code replacement. 8. Preserve the existing path, archive, ownership, size, rollback, and redirect protections; they remain valuable defense-in-depth. 9. Clearly notify the user after any successful update and require a new review or session before loading changed Skill instructions. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:34
Finding
Image-Generation Skill Requests a Shared Full-Scope Token with Unrelated Spending and Media Permissions<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37`, `scripts/authorize.py:465-476`; generic tool dispatch in `scripts/mcp_client.py:1483-1499` **Vulnerability Type**: Excessive OAuth scope and missing local tool authorization boundary **Risk Level**: High ### Vulnerable Code The authorization helper requests the following shared scope: ```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 complete scope is submitted during device authorization: ```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) ``` The client accepts an arbitrary tool name rather than enforcing a package-specific allowlist: ```python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name") ``` ```python assert tool_name is not None return session.request( 2, "tools/call", {"name": tool_name, "arguments": arguments}, ) ``` ### Technical Analysis The declared Skill functionality is to create and edit policy-digest still images from user-provided content. Its legitimate operations include model discovery, image generation/editing, optional artifact upload, task reads and user-requested cancellation, and narrowly defined wallet reads. The requested token additionally grants unrelated capabilities: - Video generation. - Music generation. - Speech generation. - Voice reading and writing. - Broad wallet spending. The documentation explicitly describes this as one shared ...[truncated 2129 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Issue a package-specific token rather than one full-scope token shared by every Beatra Skill. 2. Request only the minimum permissions required by this package, such as: - Model discovery for image capabilities. - Image generation and editing. - Artifact upload/read only when a reference is supplied. - Task read and user-authorized cancellation. - Read-only wallet balance and ledger access where explicitly requested. 3. Remove video, music, speech, voice-write, and broad wallet-spend scopes from this package. 4. Separate billing authorization from general tool access. Require explicit transaction-level user approval for paid calls. 5. Enforce a local allowlist of permissible tool names in `mcp_client.py`, rather than forwarding arbitrary values. 6. Validate each tool’s arguments locally where practical, especially count, capability, task cancellation, and paid-operation fields. 7. Use short-lived, audience-bound, package-bound credentials and support independent revocation per Skill. 8. Show the exact requested scopes on the device-authorization page in user-readable terms. 9. Avoid treating a narrower token as an error that must be replaced by a full-scope authorization. ]]>

other

Warning
Location
scripts/authorize.py:343
Finding
Hostname and Agent-Environment Metadata Are Collected, Persisted, and Transmitted<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:343-385`, `scripts/authorize.py:465-477`; recurring source telemetry in `scripts/mcp_client.py:1150-1224` and registration in `scripts/mcp_client.py:1367-1381` **Vulnerability Type**: Host identity and environment telemetry **Risk Level**: Medium ### Vulnerable Code The authorization helper inspects Agent-related environment-variable signatures: ```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" ``` It collects the local hostname: ```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 values are persisted locally: ```python def write_host_config(state_dir: Path, *, platform: str, device_name: str | None) -> None: try: payload: dict[str, Any] = {"platform": platform} if device_name: payload["device_name"] = device_name (state_dir / "host.json").write_te ...[truncated 3200 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not collect the hostname by default. Use a random opaque device identifier or a user-supplied display label. 2. Present every telemetry field before authorization, including hostname, platform, package version, and stable installation reference. 3. Require opt-in consent for a human-readable device name. 4. Provide command-line controls such as `--device-name`, `--no-device-name`, and `--telemetry off`. 5. Permit image generation without source-platform attribution unless it is strictly required for security. 6. Minimize server retention and avoid linking telemetry to content or billing records beyond operational necessity. 7. Protect `host.json` with the same private and atomic file-writing controls used for credential-adjacent state. 8. Document deletion and revocation behavior for locally persisted and server-retained telemetry. 9. If platform detection remains necessary, send only a coarse category and avoid inspecting more environment variables than required. ]]>
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
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
Findings (21)

Lp3

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The skill declares itself as a simple policy-digest layout tool, but its instructions require shell execution, filesystem access, network communication, and local state changes through a bundled client. This creates a materially larger attack surface than the apparent task requires, including credential storage, file handling, and remote operations that a user may not reasonably expect from the description.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
There is a strong description-behavior mismatch: the skill presents as a page-layout/content-generation helper but also performs authentication, persistent credential/state management, remote tool invocation, uploads, telemetry/registration, uninstall actions, and software update/install behavior. That mismatch is dangerous because it can mislead operators into granting trust and execution to a skill whose real capabilities extend well beyond the stated business purpose.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The skill includes a silent automatic self-update mechanism that downloads and replaces package-owned files without separate confirmation, even though that behavior is unrelated to generating policy digest images. Any self-modifying capability increases supply-chain and post-deployment risk because future behavior can change after review, and users may execute code different from what was originally audited.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The file documents telemetry-like installation registration behavior that is unrelated to the stated purpose of a policy-digest layout skill. Even though it is described as non-billable and best-effort, it still causes the bundled client to send host and package metadata to a backend, creating an undisclosed data flow and expanding the skill's privileges beyond what users would reasonably expect from a formatting/layout tool.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
A backend installation registration capability is not justified by the skill's declared policy-digest page layout purpose and represents unnecessary network communication. The described collection of package slug, version, platform, and stable external installation reference can enable tracking, inventorying of environments, or covert telemetry, especially because it occurs automatically on first use.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
The requested OAuth scope is far broader than the skill’s stated purpose of producing policy digest page layouts. In addition to likely-needed artifact access, it asks for images, videos, music, speech, voices, task control, and even wallet spending, which creates an unnecessary privilege set if the credential is compromised or the backend misuses the token.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
The script detects host platform from environment variables and captures a device-recognizable hostname, then persists that information to host.json. For a layout-oriented skill, this is extra host fingerprinting data that is not clearly necessary, increasing privacy risk and enabling environment profiling beyond the user’s expected task.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill records a local inventory of installed skills including absolute install paths and platform metadata in ~/.beatra/skills.json. That exceeds what is needed to render policy digest pages and can expose local filesystem structure and software inventory, which are valuable for profiling, lateral targeting, or privacy-invasive telemetry if accessed by other components.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The file implements a broad networked MCP client with credential handling, uploads, telemetry, and package update logic that is far beyond the declared purpose of generating policy digest page layouts. That mismatch materially increases attack surface and creates hidden capabilities for network communication and local state manipulation unrelated to user expectations.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code can fetch remote manifests and archives and overwrite installed package files, including via automatic update paths. Even with checksum and path validation, self-modifying behavior in a creative-layout skill is high risk because a compromised publisher, CDN, or update channel can change local code after installation.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The skill records installation telemetry and maintains a local inventory of installed skills even though this is unrelated to policy digest page creation. This creates unnecessary privacy and tracking risk and expands the code path that handles local metadata and outbound registration traffic.

Context-Inappropriate Capability

Medium
Confidence
84% confidence
Finding
The code inspects environment variables and local host metadata to classify the host platform, then uses that information in outbound requests and local registration state. For a policy-layout skill, this host fingerprinting is unnecessary and increases privacy risk while enabling environment-aware behavior not implied by the skill description.

Description-Behavior Mismatch

Medium
Confidence
93% confidence
Finding
The uninstall script manipulates shared Beatra device state and can revoke a shared authorization token, which is functionality far outside the declared purpose of a policy-digest layout skill. Even though this appears intended as lifecycle management rather than theft, bundling platform-level credential and state management into an unrelated content skill increases the blast radius if the skill is installed, invoked unexpectedly, or modified later.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
This code performs a network POST to revoke a device token using a bearer credential read from local state. For a skill whose stated purpose is policy-digest generation, outbound credential-bearing revocation logic is unnecessary and dangerous because it gives the package authority to affect account/device access beyond its business function.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The script deletes shared local Beatra state files including credentials and installation metadata from ~/.beatra. Because these files are shared across skills, a package with an unrelated functional purpose should not have direct authority to erase them; misuse or mistakes could disrupt other installed skills and destroy local authentication state.

Vague Triggers

Medium
Confidence
84% confidence
Finding
The invocation guidance is broad and underspecified, which increases the chance the skill will be selected in contexts beyond its intended scope. Over-broad routing is risky here because the skill has powerful side effects—remote calls, uploads, local persistence, and shell use—so accidental invocation could trigger unnecessary exposure or account actions.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The automatic update feature modifies local package files without an upfront warning or separate confirmation. This undermines informed consent and auditability, and it creates a path for reviewed behavior to change silently over time, which is especially sensitive in a skill already using shell, network, and local file capabilities.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The document states that the client silently checks for updates and automatically installs newer releases without separate confirmation. Even though it describes integrity checks and rollback protections, enabling file-replacing updates by default can still create meaningful user-impacting risk because local software is modified without an explicit approval step at update time, which can surprise users, affect reproducibility, or amplify damage if the trusted update channel is ever compromised.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The maybe_auto_update() path silently checks for and applies updates, modifying installed package files without contemporaneous user warning. Hidden mutation of executable package contents undermines user trust and makes it harder to audit what code actually ran during a session.

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
94% confidence
Finding
This function reads ~/.beatra/credentials.json and extracts an access token for subsequent use in a revocation request. Direct credential access by a skill package is high risk because any code with token-reading capability can potentially repurpose, misuse, or leak those credentials, and the skill's declared policy-layout context does not justify such access.

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 CLI advertises and enables package self-update behavior, confirming that this skill is designed to modify its own installed code. In the context of a policy digest page generator, that capability is unnecessary and dangerous because it allows post-installation code changes outside normal review expectations.

Static analysis

No suspicious patterns detected.