Back to skill

Security audit

Duty Board Pack

Security checks for vulnerabilities and agentic risk

Overview

The skill can make classroom duty-board images, but it also requests broad persistent Beatra access and silently updates its own package files, which exceeds the narrow advertised purpose.

Review this skill before installing in managed, school, or business environments. It is not just a classroom-board prompt template: it creates a persistent Beatra connection, may spend credits through Beatra tools after approval, can upload selected local files, records installation metadata, and silently updates package files unless automatic updates are turned off. Install only if you trust Beatra's credential storage, update channel, and broad shared MCP access model.

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 (4)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:34
Finding
Authorization Requests Privileges Beyond the Skill's Declared Functionality<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37` **Vulnerability Type**: Excessive OAuth authorization 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 is declared as a classroom duty-board image generator. Its legitimate functionality requires image generation and editing, optional reference-image upload, model lookup, billing access, and limited task management. The requested authorization scope additionally includes: - `videos:generate` - `music:generate` - `speech:generate` - `voices:read` - `voices:write` These privileges are unrelated to generating duty-board images. The package documentation explicitly confirms that a single approval covers image, video, music, speech, upload, model, and task tools in `references/installation-and-auth.md:73-74`. This violates the principle of least privilege. The credential is also shared across Beatra Skills, which increases the consequences if the token or bundled client is misused. ### Attack Path 1. The user runs `scripts/authorize.py`. 2. The script requests the complete scope defined by `SCOPE`. 3. The user approves the device authorization. 4. Beatra returns a bearer token containing permissions for unrelated media and voice operations. 5. The token is stored in `~/.beatra/credentials.json`. 6. A malicious instruction, compromised future update, or local process with access to the token invokes unrelated paid media or voice tools. 7. The request executes with privileges that were unnecessary for the duty-board task. ### Impact Assessment An attacker able to misuse the credential could potentially: - Generate images, videos, music, and speech. - Read or modify voice-related resources. - Upload artifacts. - Spend wallet credits. - Read a ...[truncated 225 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the full shared scope with a package-specific least-privilege scope. 2. Request only the capabilities necessary for this Skill, such as: - Image model listing. - Image generation and editing. - Artifact upload and retrieval. - Read-only wallet pricing or balance access where required. - Task read access and user-authorized cancellation. 3. Remove video, music, speech, and voice-write permissions. 4. Separate read-only permissions from paid or state-changing permissions. 5. Use a package-specific credential rather than a shared full-scope device token. 6. Display the exact requested permissions to the user before opening the authorization page. 7. Add automated tests that fail if unrelated scopes are added to this image-only package. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/mcp_client.py:1458
Finding
Bundled Client Permits Arbitrary MCP Tool Invocation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:1458-1477` **Vulnerability Type**: Unrestricted privileged tool dispatch **Risk Level**: High ### Vulnerable Code ```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}, ) ``` The command-line parser accepts the tool name without an allowlist: ```python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name") ``` ### Technical Analysis The bundled client forwards any caller-supplied `tool_name` to the remote MCP service. It does not restrict dispatch to the tools required by the duty-board workflow. This behavior is particularly dangerous because the client automatically loads the shared bearer token from `~/.beatra/credentials.json`. That token is requested with broad media-generation, wallet-spending, artifact, voice, and task scopes. Input arguments being restricted to a JSON object does not mitigate the authorization issue. The security-sensitive field is the unrestricted tool name itself. A prompt-injected agent command, operator mistake, or compromised package instruction can therefore attempt any tool authorized by the credential. ### Attack Path 1. The user authorizes the Skill and receives the broad bearer credential. 2. An atta ...[truncated 1042 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Implement a hardcoded allowlist of tool names required by this Skill. 2. Permit only narrowly necessary operations, for example: - `beatra.models.list` - `beatra.images.generate` - `beatra.images.edit` - `beatra.assets.upload` - Required task read, list, and user-approved cancel operations. - Explicitly required read-only wallet operations. 3. Reject every unrecognized tool before creating an authenticated session. 4. Maintain separate allowlists for read-only and paid or state-changing calls. 5. Require explicit user confirmation immediately before each paid or destructive operation. 6. Validate arguments locally against per-tool schemas. 7. Avoid exposing `tools/list` in production if it unnecessarily reveals account capabilities. 8. Add tests demonstrating that unrelated media, voice, wallet-spending, and administrative tool names are rejected locally. ]]>

other

Warning
Location
scripts/authorize.py:339
Finding
Authorization Collects and Transmits Host-Identifying Telemetry<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:339-366`, `scripts/authorize.py:456-468` **Vulnerability Type**: Environment reconnaissance and device fingerprinting **Risk Level**: Medium ### Vulnerable Code The script detects the executing agent from environment variables: ```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" 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 values are added to 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_ ...[truncated 2045 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Remove `socket.gethostname()` collection from the default authorization flow. 2. Use the random installation reference as the device identifier. 3. Default the platform value to `unknown` unless the user explicitly opts into platform reporting. 4. Present all transmitted metadata fields before authorization begins. 5. Make diagnostic and product-analytics telemetry opt-in. 6. Provide a configuration option that disables hostname, platform, registration, and source-attribution telemetry. 7. Minimize retention and correlation of stable installation identifiers server-side. 8. Document the purpose, retention period, and deletion procedure for every transmitted field. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:969
Finding
Default Silent Self-Update Can Replace Executable Package Code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:515-522`, `scripts/mcp_client.py:969-1017`, `scripts/mcp_client.py:1517-1544` **Vulnerability Type**: Automatic remote payload retrieval and code replacement **Risk Level**: High ### Vulnerable Code Automatic updating is enabled when update state is absent or invalid: ```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 ``` Ordinary commands perform a silent update check and can apply downloaded files: ```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 ): re ...[truncated 3762 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. 2. Make ordinary commands check for updates only after explicit user opt-in. 3. Notify the user of an available version and require confirmation before replacing executable files. 4. Sign release metadata and archives with an offline-controlled signing key. 5. Embed only the verification public key in the package. 6. Verify signatures independently of HTTPS and SHA-256 metadata served by the release infrastructure. 7. Add signed rollback-protection metadata, including package identity, release sequence, channel, and expiration. 8. Separate update checking from authenticated business operations so an update failure or compromise cannot affect a paid request. 9. Run updates in a restricted process without access to the bearer credential. 10. Preserve the existing archive validation, ownership checks, locking, transactional replacement, and rollback protections as defense-in-depth. ]]>
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
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (28)

Lp3

Medium
Category
MCP Least Privilege
Confidence
96% confidence
Finding
The skill declares a narrow classroom duty-board purpose, but the content instructs use of shell commands, network access, local file access, and package mutation without any explicit permission declaration. This creates an unnecessarily broad execution and data-access surface, making it easy for the skill to access local state, transmit data, or modify files in ways the user would not reasonably expect from a graphics-generation workflow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented behavior materially exceeds the stated purpose: beyond generating duty-board images, it performs authentication, credential storage, arbitrary Beatra tool invocation, local file upload, telemetry/registration, uninstall actions, and self-update behavior. This mismatch is dangerous because users may grant trust based on the benign description while the skill actually gains access to credentials, files, network actions, and software lifecycle operations.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
Wallet balance and billing-ledger access are not strictly necessary for producing classroom duty-board images, and they expose sensitive financial/account metadata. Even if read-only, such access expands the data scope of the skill and can leak account information or be used for profiling, especially when the manifest does not clearly disclose this broader access pattern.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill includes silent automatic self-updates that download, verify, and replace package-owned files without separate confirmation, despite presenting itself as a classroom content-generation tool. Any mechanism that can modify installed code at runtime materially raises supply-chain and persistence risk; if the update channel, signing, or client logic is compromised, the skill becomes a path for arbitrary code delivery under the guise of normal use.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
Automatic download, installation, rollback, and file replacement are far outside the expected scope of a duty-board creation skill and create a direct code- and filesystem-modification pathway. In this context, the mismatch makes the behavior more dangerous because users interacting with a simple classroom asset workflow are unlikely to expect or scrutinize software-update behavior, increasing the chance of silent abuse or compromise.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
The manifest describes a harmless classroom duty-board graphics skill, but the changelog references adding balance and ledger calls and removing a hardcoded top-up address and tier pricing. That mismatch strongly suggests hidden financial functionality unrelated to the declared purpose, which is a classic sign of deceptive capability smuggling and could enable unauthorized access to financial data or payment workflows.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
Balance and ledger access are not justified by a duty-board image-generation workflow, so their presence indicates excessive privileges with no legitimate need in context. If connected to real user accounts, these capabilities could expose sensitive financial history or support account reconnaissance for later abuse.

Description-Behavior Mismatch

High
Confidence
98% confidence
Finding
This file is materially unrelated to the stated classroom duty-board skill and instead provides detailed instructions for installing Beatra, obtaining persistent credentials, and connecting to a remote MCP endpoint. In a narrowly scoped content-generation skill, unrelated auth and remote-service setup is a strong indicator of hidden capability expansion or supply-chain abuse.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The instructions direct the agent to obtain and persist a long-lived Device Token and use it to access a broad external MCP tool surface spanning multiple tool classes unrelated to the declared skill purpose. This creates unjustified external connectivity and credential persistence that could enable unauthorized actions, data exfiltration, or later misuse far beyond generating classroom board graphics.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The script requests a very broad OAuth scope set including artifacts, images, videos, music, speech, voices, wallet spending, and task control, which is far beyond the described purpose of generating still classroom duty boards. Over-scoped credentials violate least privilege and materially increase blast radius if the token is misused, leaked, or if the package behavior changes later.

Context-Inappropriate Capability

Critical
Confidence
99% confidence
Finding
The script requests `videos:generate` despite the skill being framed as a still-image board generator. Unnecessary video-generation access broadens what the token can do and increases abuse potential without matching user expectations for this package.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script requests `videos:generate` despite the skill being framed as a still-image board generator. Unnecessary video-generation access broadens what the token can do and increases abuse potential without matching user expectations for this package.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
The script requests `videos:generate` despite the skill being framed as a still-image board generator. Unnecessary video-generation access broadens what the token can do and increases abuse potential without matching user expectations for this package.

Description-Behavior Mismatch

High
Confidence
95% confidence
Finding
The client exposes broad remote MCP tool invocation, local file upload, registration telemetry, and package updating features that materially exceed the advertised classroom duty-board generation scope. In a skill ecosystem, this scope mismatch is dangerous because users and hosts may grant trust based on the declared creative purpose while the code can perform unrelated networked operations and send local data off-device.

Context-Inappropriate Capability

High
Confidence
94% confidence
Finding
This code downloads manifests and archives from remote infrastructure and replaces local package files, including automatic silent updates during normal execution. Even with checksum and path validations, remote self-modification greatly expands the trust boundary and creates a supply-chain execution path unrelated to a simple duty-board generator.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The client records local skill inventory and registers installation telemetry to a remote service despite this behavior not being necessary for classroom duty-board generation. Undisclosed telemetry increases privacy risk and weakens the principle of least surprise, especially in educational or managed-device environments.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
This uninstall script manages a shared device credential and deletes global Beatra state under ~/.beatra, which is materially broader than the declared purpose of generating classroom duty-board graphics. Even if framed as cleanup logic, bundling account/session revocation into an unrelated content-generation skill creates unnecessary authority and can disrupt other installed skills or the user's broader agent environment.

Context-Inappropriate Capability

Medium
Confidence
91% confidence
Finding
The script contains outbound network capability to call a revocation endpoint and act on device authorization state, which is unrelated to the skill's classroom board-generation function. That expands the attack surface and gives this package the ability to affect account/session state beyond its business purpose.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code reads credentials.json and removes multiple files in shared ~/.beatra state, including installation and registration metadata used by all skills. In the context of a duty-board creation skill, this is over-privileged behavior that can delete shared configuration, invalidate sessions, and interfere with unrelated skills on the device.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The document explicitly states that the client silently checks for updates and installs newer releases automatically without separate confirmation. Even though the text describes integrity checks and fixed update sources, unprompted modification of installed files increases supply-chain and operational risk because users may be unaware that executable or package content can change before normal commands run.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The document states that on first use the client automatically sends installation metadata and writes a local cache file, but it does not clearly warn users up front that telemetry-like registration and filesystem modification will occur. Even though the data described is limited and non-secret, silent automatic reporting and local state changes can violate user expectations, privacy requirements, or organizational policy in security-sensitive environments.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
Automatic silent self-update changes installed code during routine execution without a contemporaneous user-facing warning or approval step. In the context of a narrowly described classroom graphics skill, silent code replacement is especially risky because it can alter behavior and permissions outside user expectations.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
the user signs in or creates their account there, and the approval page
  continues automatically after sign-in;
- say once that the connection continues automatically after Allow, then
  detect completion yourself — never ask the user to confirm in chat that
  they approved.

Approval legitimately takes minutes when sign-in or account creation is
Confidence
88% confidence
Finding
The instruction to 'never ask the user to confirm' encourages autonomous progression through a sensitive authorization flow without an explicit user acknowledgment checkpoint in chat. In the context of acquiring remote service credentials, reducing user confirmation can weaken informed consent and make stealthier account linking or authorization abuse easier.

Credential Access

High
Category
Privilege Escalation
Content
- `~/.beatra/installation.json` contains one stable, non-secret installation
  reference.
- `~/.beatra/credentials.json` contains the single Device Token.

On POSIX systems the directory must be mode `0700` and both files mode `0600`.
On Windows the current user must be the only principal granted access through
Confidence
91% confidence
Finding
This documentation instructs storage and use of a Device Token in a local credentials file for a skill whose stated purpose does not justify credentialed remote access. Even though it mentions restrictive file permissions, introducing persistent bearer-token handling into an unrelated skill expands the attack surface and creates a reusable secret that could be abused if the skill or host is compromised.

Credential Access

High
Category
Privilege Escalation
Content
4. polls every 5 seconds for up to 15 minutes while the user signs in (or
   creates their account) and selects Allow;
5. atomically saves the returned Device Token to
   `~/.beatra/credentials.json` without printing an HTTP response body;
6. validates the new credential with the same non-billable MCP request and
   prints Ready only after it succeeds.
Confidence
93% confidence
Finding
The flow explicitly saves a returned Device Token to a persistent local file, creating durable credential material for an external service. In the context of a classroom duty-board generator, this is unnecessary and dangerous because a stolen bearer token could grant ongoing access to the remote MCP service and any linked capabilities.

Static analysis

No suspicious patterns detected.