Back to skill

Security audit

KYC Guide Set

Security checks for vulnerabilities and agentic risk

Overview

This skill can generate the advertised KYC stills, but it also requests broad Beatra account powers and silently updates executable package files.

Review this before installing, especially in corporate or regulated environments. Only install if you are comfortable granting a shared Beatra device credential with broad media and billing-related powers, sending KYC-related prompts or selected files to Beatra, allowing hostname/platform attribution, and accepting silent package updates unless you immediately disable them with the provided update setting.

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:33
Finding
Overprivileged OAuth Scope and Unrestricted Remote Tool Dispatch<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:33-37`; `scripts/mcp_client.py:1462-1479` **Vulnerability Type**: Excessive authorization scope and missing tool allowlist **Risk Level**: High ### Complete Code Snippets ```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" ) ``` ```python 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 Skill's declared purpose is to create a set of still KYC guide images. Its documented workflow requires image generation and editing, model discovery, optional artifact upload, task inspection and recovery, and read-only billing information. The requested OAuth scope is substantially broader. It includes video, music, speech, voice write/read, unrestricted artifact writes, wallet spending, and task cancellation. The bundled client also accepts an arbitrary tool name from the command line and forwards it to the remote MCP service without enforcing a package-specific allowlist. The remote service may still perform its own authorization and schema checks, but the local client does not preserve the Skill's least-privilege boundary. A bearer token obtained for this image-oriented Skill is capable of authorizing unrelated operations. ### Attack Path 1. A user authorizes the KYC image Skill. 2. The authorization helper obtains a bearer token with the complete broad scope. 3. A malicious instruction, compromised future package update, or accidental command invokes: `python3 scrip ...[truncated 800 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared broad scope with a package-specific minimum scope containing only: - image generation and editing; - model listing; - narrowly required artifact upload/read access; - read-only wallet access; - task read access; and - task cancellation only if cancellation is an explicitly supported user operation. 2. Remove video, music, speech, and voice permissions from this Skill. 3. Separate wallet spending from general tool authorization where the service supports granular scopes. 4. Add a hardcoded local allowlist in `_run_command`, for example: - `beatra.models.list` - `beatra.images.generate` - `beatra.images.edit` - `beatra.assets.upload` - `beatra.tasks.get` - `beatra.tasks.list` - `beatra.tasks.cancel` - `beatra.wallet.get` - `beatra.wallet.ledger` 5. Reject every unrecognized tool before creating an MCP request. 6. Use separate credentials per package or capability if the Beatra platform cannot issue sufficiently narrow shared tokens. 7. Add automated tests proving that unrelated media, voice, and wallet-spending tools are rejected locally. ]]>

other

Warning
Location
scripts/authorize.py:347
Finding
Hostname and Agent-Environment Information Transmitted Without Being Required for Image Generation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:347-370`, `scripts/authorize.py:448-459`; `scripts/mcp_client.py:1231-1238` **Vulnerability Type**: Environment reconnaissance and unnecessary telemetry **Risk Level**: Medium ### Complete Code Snippets ```python 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] ``` ```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 ``` ```python arguments.setdefault("source_package_slug", PACKAGE_SLUG) arguments.setdefault("source_platform", host_platform()) ``` ### Technical Analysis The authorization helper identifies the Agent runtime by inspecting process-environment signatures, obtains the system hostname, and sends both the platform and device name to the Beatra authorization service. The detected information is also persisted in `~/.beatra/host.json`. Subsequent business calls receive package and platform attribution. The audit did not find collection of IP addresses or FQDNs. Nevertheless, the hostname can reveal internal naming conventions, usernames, corporate asset identifie ...[truncated 1420 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not collect or transmit the hostname by default. 2. Generate a random, non-identifying device alias for console display. 3. Make descriptive device naming explicitly opt-in and show the exact value before transmission. 4. Avoid inspecting Agent-specific environment variables unless platform identification is required for a documented compatibility feature. 5. Provide a telemetry-disabled mode that omits `platform`, `device_name`, `source_platform`, and package-registration telemetry. 6. Document: - every collected field; - its purpose; - its retention period; - whether it is shared with third parties; and - how the user can delete it. 7. Restrict `host.json` to private permissions consistently on all supported platforms. 8. Minimize correlation by rotating or scoping installation identifiers where persistent cross-session identity is unnecessary. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Default Silent Self-Update Allows Post-Audit Replacement of Executable Skill Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:31-32`, `scripts/mcp_client.py:969-1018`; `SKILL.md:163-182` **Vulnerability Type**: Remote payload retrieval and automatic executable-code replacement **Risk Level**: High ### Complete Code Snippets ```python PACKAGE_DISCOVERY_URL = "https://beatra.ai/skills/kyc-guide-set/channels/clawhub/install.json" PACKAGE_CDN_BASE_TEMPLATE = "https://cdn.beatra.ai/agent-packages/kyc-guide-set/channels/clawhub/v{version}" ``` ```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_ho ...[truncated 3019 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. 2. Permit automatic update checks, but require explicit user approval before replacing executable files. 3. Sign release metadata with a dedicated offline or hardware-protected signing key. 4. Embed or securely provision the corresponding public key in the audited client. 5. Verify a signed statement binding: - package name; - release channel; - version; - archive digest; - manifest digest; and - expiration or publication time. 6. Use threshold signing or a transparency log for higher assurance. 7. Display the current and target versions and a verified release summary before installation. 8. Preserve an enterprise policy to disable updates centrally. 9. Continue the existing path, size, rollback, ownership, redirect, and downgrade protections; they are valuable but should supplement rather than replace authenticated release signing. 10. Ensure updating cannot occur before security-sensitive commands unless the user has explicitly enabled that behavior. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/mcp_client.py:229
Finding
Server-Supplied Upload URL Is Not Restricted to an Approved Storage Host<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:229-252` **Vulnerability Type**: Insufficient validation of remote upload destination **Risk Level**: High ### Complete Code Snippet ```python 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) ``` ### Technical Analysis The upload helper requests an upload grant from the Beatra MCP service and then performs an HTTP `PUT` to the URL returned in that response. It verifies that the URL uses HTTPS, has a hostname, contains no embedded credentials, and has no fragment. It also validates the declared content type and content length. It does not verify that the destination hostname belongs to Beatra or an explicitly approved object-storage service. Therefore, any HTTPS origin is accepted. HTTPS protects the connection to the selected destination, but it does not establish that the destination is authorized to receive the user's file. The vulnerability requires a compromised or malicious MCP response, or compromise of the server component that issues upload grants. Nevertheless, client-side destination restrictions are important because uploaded KY ...[truncated 1142 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Enforce an exact allowlist of approved upload hostnames. 2. If uploads use dynamic storage subdomains, validate them against a strict suffix while preventing lookalike domains; for example, require either an exact hostname or a subdomain boundary ending in `.approved-storage.example`. 3. Reject non-default ports unless specifically required. 4. Bind upload grants cryptographically to: - the approved storage origin; - artifact identifier; - content digest; - content length; - MIME type; and - short expiration time. 5. Verify the grant signature locally before transmitting file bytes. 6. Prefer returning an opaque grant identifier that the client resolves only through a fixed trusted endpoint. 7. Display the destination organization or approved storage service before uploading sensitive KYC material. 8. Add tests proving that arbitrary HTTPS hosts, deceptive suffixes, IP literals, and unexpected ports are rejected. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (34)

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill declares a narrow KYC guide-generation purpose, yet its instructions require shell execution, local file access, network access, and package modification behaviors through a bundled client. This creates a much broader capability surface than users would reasonably expect, increasing the risk of credential exposure, unintended data transfer, or execution of code paths unrelated to the stated task.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The documented behavior materially exceeds the advertised function by introducing authentication flows, persistent credential storage, remote service communication, uploads, telemetry/registration, and uninstall/revocation logic. This mismatch undermines informed consent and can cause users to expose sensitive KYC-related materials or authorize broad account access without understanding the full operational scope.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
Embedding automatic self-update behavior inside a content-generation skill adds a software supply-chain mechanism unrelated to the core KYC still-generation task. Even if verification is claimed, this enlarges the trust boundary and permits code changes after installation, which is especially concerning in a workflow handling sensitive onboarding materials.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
Automatic download and installation are unjustified for a KYC guide generation skill and create a direct supply-chain risk: future code can be fetched and installed in an environment that may also hold account-opening data or credentials. The presence of file replacement and rollback logic confirms the skill can modify local package-owned files, which is a strong capability escalation beyond simple asset generation.

Description-Behavior Mismatch

Medium
Confidence
96% confidence
Finding
The manifest advertises a narrow, local content-transformation skill, yet it wires the skill to an authenticated remote MCP endpoint. That creates a capability mismatch: user inputs and possibly other context may be transmitted to an external service with broader powers than the stated task requires, which is a classic indicator of over-privileged design and potential data exfiltration risk.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
Device-bearer authentication plus a local credential file is not justified for generating KYC guide stills from checklist text. Even if the skill does not explicitly expose secrets, binding it to stored credentials unnecessarily expands trust and creates a path for unauthorized account access, token misuse, or sensitive data transfer to a remote service.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
This documentation describes a self-updating client, including silent update checks and automatic installation, which is unrelated to a KYC checklist-to-guide skill. That mismatch is dangerous because it suggests the skill bundle may include or normalize behavior that modifies local software outside the user’s expected task scope, increasing supply-chain and trust-boundary risk.

Context-Inappropriate Capability

Medium
Confidence
98% confidence
Finding
The file explicitly documents silent, enabled-by-default automatic update checks and unattended installation for a skill whose stated purpose is generating KYC guide stills. In this context, such capability is unjustified and risky because it can change executable files during ordinary use, creating a strong supply-chain attack surface and violating user expectations about a content-generation skill.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This file introduces a full networked installation and authorization flow for Beatra that is unrelated to the stated purpose of converting KYC checklist lines into still-guide content. That scope mismatch is dangerous because it expands the skill from local content transformation into credentialed remote service access, creating an unexpected capability channel users would not reasonably expect from this skill.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill contains instructions for storing a device token, performing device authorization, and invoking a remote MCP endpoint despite the declared skill purpose not justifying credential management or remote execution. This creates hidden privileged behavior and increases the risk of unauthorized data transfer, token misuse, and user deception about what the skill actually does.

Description-Behavior Mismatch

Medium
Confidence
92% confidence
Finding
The file describes installation registration, platform detection, host identification, and caching behavior that are unrelated to a checklist-to-KYC-guide rendering skill. This mismatch is dangerous because it indicates the skill may perform hidden telemetry or environment-aware behavior outside user expectations, increasing the risk of undisclosed data collection and supply-chain abuse.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The documented capability to register package installations and identify the real agent environment is unjustified for a content-generation skill that should only transform checklist lines into still-guide output. Such extra capability broadens the attack surface and can enable tracking, profiling, or later conditional behavior based on host environment, which is especially suspicious given the unrelated business purpose.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The OAuth scope set is vastly broader than the skill's stated purpose of generating still-image KYC guide content from checklist lines. It includes wallet spending plus audio, voice, video, and task-management permissions, violating least privilege and creating a high-risk over-authorization condition if the skill, package, or account is ever abused or compromised.

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
The skill requests music, speech, and voice read/write/generate privileges even though the package description is limited to creating still KYC guide sets and materials graphics. These unrelated media scopes materially expand what the credential can do if stolen or misused, enabling actions far outside user expectations.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The skill requests music, speech, and voice read/write/generate privileges even though the package description is limited to creating still KYC guide sets and materials graphics. These unrelated media scopes materially expand what the credential can do if stolen or misused, enabling actions far outside user expectations.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The inclusion of tasks:read and tasks:cancel is not supported by the stated purpose of turning checklist lines into still-image guides. While less severe than wallet access, these permissions can expose or interfere with other user operations and represent unnecessary authority beyond the expected workflow.

Description-Behavior Mismatch

High
Confidence
92% confidence
Finding
The advertised skill purpose is a narrow KYC checklist-to-guide generator, but this file exposes a general networked MCP client with tool invocation, uploads, registration, and update capabilities. That mismatch is dangerous because it expands the operational and trust boundary far beyond user expectations, enabling remote actions unrelated to the declared function and increasing the blast radius if the backend or package is abused.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The code fingerprints the host platform and registers installation telemetry even though that behavior is not necessary for turning checklist text into KYC guide stills. In this context, hidden collection of environment metadata is more suspicious because the declared creative skill gives users little reason to expect tracking or device inventory behavior.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
Self-update logic downloads manifests and archives from remote infrastructure and rewrites installation files, which is unrelated to the narrow creative purpose described for the skill. Even with checksum validation, embedding a full updater in a content-generation skill increases the attack surface and gives the package the ability to change its own behavior after installation.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
This uninstall script handles shared Beatra device credentials and can revoke a remote OAuth authorization, which is unrelated to the advertised KYC guide-generation purpose of the skill. Even if framed as uninstall logic, bundling credential and shared-state management into a content-generation skill creates unnecessary privileged access and increases the risk of unauthorized disruption of other installed skills or account connectivity.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The code performs a network call to the Beatra OAuth revocation endpoint during uninstall, giving this skill authority to alter account/device authorization state over the network. That capability is not justified by a KYC guide creation skill and expands the attack surface to remote credential invalidation, service disruption, and covert side effects outside the user's expected workflow.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
This code reads the shared access token from ~/.beatra/credentials.json and deletes multiple shared state files from ~/.beatra, which exceeds the permissions needed for generating KYC guide stills. Access to shared credentials and deletion of shared installation metadata can expose secrets and break unrelated skills that rely on the same state directory.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
Installing updates silently at invocation time without a contemporaneous warning deprives users of a meaningful chance to assess changed code before execution. In a skill that touches local files, credentials, and remote services, silent updates materially increase the risk of unnoticed behavior changes or compromise through the update channel.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The markdown states that ordinary commands trigger a silent update check and that higher versions are installed automatically without separate confirmation. Even if integrity checks are described, modifying local files during unrelated user actions without upfront warning or consent is unsafe because it reduces transparency and can enable unwanted code changes through the update channel.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The markdown states that a background `beatra.installations.register` call sends package slug, version, platform, and installation reference on first use, but it does not mention explicit warning, consent, or an opt-in flow. Silent metadata transmission is dangerous because it can expose deployment and environment information without user awareness, creating privacy, compliance, and trust risks.

Static analysis

No suspicious patterns detected.