Back to skill

Security audit

coworking-day-pack

Security checks for vulnerabilities and agentic risk

Overview

This playlist skill is marked for Review because it bundles a broad Beatra client with account credentials, file upload, and silent self-update capabilities beyond a simple office-music workflow.

Review this carefully before installing. Only use it if you trust Beatra with a shared broad device credential, silent package updates, installation telemetry, and a client that can upload local files when invoked. Prefer disabling automatic updates and avoid using the upload or generic tool-call paths unless you explicitly need them.

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)

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:34
Finding
Authorization Scope and Local Upload Capability Exceed the Skill's Music-Generation Requirements<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:34-37`; `scripts/mcp_client.py:191-223`; `scripts/mcp_client.py:1438-1446` **Vulnerability Type**: Excessive OAuth permissions and unnecessary local-file upload capability **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 bundled client also implements arbitrary local-file reading for uploads: ```python def _read_local_upload(path: Path) -> tuple[str, bytes]: candidate = path.expanduser() descriptor = -1 try: flags = os.O_RDONLY | getattr(os, "O_NOFOLLOW", 0) descriptor = os.open(candidate, flags) before = os.fstat(descriptor) if ( not stat.S_ISREG(before.st_mode) or before.st_size < 1 or before.st_size > MAX_UPLOAD_BYTES ): raise RuntimeError( f"Local upload must be one regular file between 1 and {MAX_UPLOAD_BYTES} bytes" ) with os.fdopen(descriptor, "rb") as handle: descriptor = -1 content = handle.read(MAX_UPLOAD_BYTES + 1) after = os.fstat(handle.fileno()) stable_fields = ("st_dev", "st_ino", "st_size", "st_mtime_ns") if ( len(content) != before.st_size or len(content) > MAX_UPLOAD_BYTES or any(getattr(before, field) != getattr(after, field) for field in stable_fields) ): raise RuntimeError("Local upload changed while it was being read") except RuntimeError: raise except OSError as exc: raise RuntimeError("Local upload must be one readable regular file") from exc finally: if descriptor >= 0: os.close(descriptor) return candidate.name, content ``` The upload command passes the resulting cont ...[truncated 3412 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace the shared broad scope with a package-specific, least-privilege authorization grant. 2. Limit the grant to music generation, model or price lookup, necessary task reads, result reads, and narrowly scoped billing operations. 3. Remove these scopes unless a separately declared and user-approved workflow requires them: - `images:generate` - `videos:generate` - `speech:generate` - `voices:read` - `voices:write` - Generic `artifacts:write` - Generic `tasks:cancel` 4. Replace general `wallet:spend` authority with a service-side permission restricted to music generation, if the platform supports capability-specific spending. 5. Remove the local upload command from this package. If upload is retained for another documented workflow: - Require an explicit user confirmation naming the exact file. - Restrict files to a user-selected workspace or allowlisted directory. - Display the destination hostname and file size before transmission. - Reject credential files, SSH material, environment files, and other known-sensitive paths. 6. Add a local allowlist of MCP tool names appropriate to this Skill rather than accepting arbitrary tool names. 7. Use separate credentials per package or per capability so compromise of one Skill cannot exercise unrelated Beatra services. ]]>

other

Warning
Location
scripts/authorize.py:339
Finding
Authorization Collects and Transmits Hostname and Agent-Environment Metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:339-380`; `scripts/authorize.py:444-467`; `scripts/authorize.py:566-569` **Vulnerability Type**: Environment reconnaissance and device telemetry **Risk Level**: Medium ### Vulnerable Code The authorization helper detects the Agent platform by inspecting process-environment 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 also 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 results are persisted locally: ```python def write_host_config(state_dir: Path, *, platform: str, device_name: str | None) -> None: """Persist detection results so mcp_client never re-detects per request and still has a truth source when its own env detection comes up empty. Best-effort: config failure must never block authorization.""" try: ...[truncated 3105 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make hostname and Agent-platform telemetry opt-in rather than automatic. 2. Before collecting or transmitting metadata, clearly disclose: - The exact fields collected. - Their destination. - Their retention and intended use. 3. Do not send the operating-system hostname by default. Generate a random, non-identifying device label or allow the user to enter one. 4. Allow authorization to proceed without `device_name`, platform fingerprinting, or installation telemetry. 5. Avoid persisting the hostname in `~/.beatra/host.json` unless the user explicitly enables device labeling. 6. If platform information is operationally necessary, send a coarse value such as `agent` or `unknown` rather than identifying a specific Agent product. 7. Apply restrictive permissions to `host.json` consistently, including when it is written directly rather than through the existing atomic private-file helper. 8. Document server-side retention, deletion, and correlation controls for installation telemetry. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
SKILL.md:143
Finding
Silent Automatic Updates Permit Remote Replacement of Executable Skill Files<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:143-163`; `references/automatic-updates-and-safety.md:3-19`; `scripts/mcp_client.py:969-1009`; `scripts/mcp_client.py:1543` **Vulnerability Type**: Silent remote payload retrieval and package code replacement **Risk Level**: High ### Vulnerable Code and Instructions The Skill explicitly enables silent automatic replacement: ```markdown ## Runtime and safe automatic updates The bundled client silently checks for a newer release at most once every 24 hours per installation. When a newer version is available, it installs automatically without separate confirmation. It downloads only from the fixed official Beatra discovery and immutable CDN paths for this package, channel, and locale, verifies discovery data, archive, manifest, and every packaged file, and replaces only package-owned files. Update checks, downloads, verification, replacement, rollback, and recovery fail open: the current installation remains usable and the original command continues. An update failure never authorizes retrying a paid music request. The setting persists for this installation. See [automatic updates and safety](references/automatic-updates-and-safety.md). ```text python3 scripts/mcp_client.py update --auto off python3 scripts/mcp_client.py update --auto on python3 scripts/mcp_client.py update --check ``` ``` The automatic update function is invoked before ordinary command processing: ```python maybe_auto_update() ``` The updater relies on release metadata containing archive and manifest hashes: ```python or not isinstance(discovery.get("archive_sha256"), str) or _SHA256.fullmatch(discovery["archive_sha256"]) is None or not isinstance(discovery.get("manifest_sha256"), str) or _SHA256.fullmatch(discovery["manifest_sha256"]) is None ``` ### Technical Analysis The bundled client periodically contacts a fixed Beatra discovery URL and CDN, downloads a package archive and manifest, verifies hashes and file metadat ...[truncated 2934 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic installation of updates by default. 2. Permit silent update checks only; require explicit, informed confirmation before downloading or replacing package files. 3. Display the publisher, current version, target version, changed files, release notes, and requested permission changes before installation. 4. Sign release manifests with an offline-protected publisher key and embed or securely pin the verification public key in the client. 5. Verify a cryptographic signature over the complete manifest, package identity, version, channel, archive digest, and file list. Remote hashes alone are insufficient if release metadata and archives share the same trust boundary. 6. Add signed rollback protection or a transparency log so a compromised service cannot arbitrarily rewrite release history. 7. Do not automatically continue into a privileged or billable operation after package replacement. Require a fresh process and renewed user confirmation. 8. If an update adds scopes, tools, network destinations, telemetry, or filesystem access, require a new authorization and explicit approval. 9. Provide an immutable-version mode and document `update --auto off` prominently during installation rather than only after automatic updates have already been enabled. 10. Log update decisions and verified signer identities without logging credentials, prompts, or other sensitive data. ]]>
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 (26)

Lp3

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding
The skill declares a narrow music-playlist purpose but documents capabilities equivalent to a local executable client with network, shell, file, and credential-handling behavior. Undeclared powerful capabilities reduce transparency and expand the attack surface, especially because users may invoke the skill expecting simple content generation rather than code execution, remote calls, and local state changes.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
This is a significant description-behavior mismatch: the skill presents itself as a playlist tool while also performing authentication flows, persistent credential storage, arbitrary remote MCP tool invocation, uploads, telemetry/registration, uninstall state deletion, and automatic software updates. That mismatch is dangerous because it can mislead users and hosting agents into granting trust or execution to functionality far beyond the stated business purpose, enabling supply-chain compromise, credential exposure, or unauthorized remote operations.

Description-Behavior Mismatch

Medium
Confidence
95% confidence
Finding
The documentation includes self-updating package behavior that is operationally unrelated to generating coworking playlists, which introduces a software supply-chain pathway into an otherwise content-generation skill. Even with claimed verification, self-update logic increases risk because any compromise of discovery, signing, distribution, or update implementation can lead to silent code replacement on the host.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Automatic remote download and installation is not justified by the stated playlist-creation function, so it represents unnecessary high-risk functionality. Unnecessary updater code broadens the attack surface and creates a path for remote code changes that users would not reasonably expect from a music-playlist skill.

Description-Behavior Mismatch

Medium
Confidence
94% confidence
Finding
The file gives the skill broad operational guidance for asynchronous task polling, task recovery, cancellation behavior, billing interpretation, and media-task handling that goes well beyond the stated purpose of creating a coworking office playlist. This scope expansion can enable unnecessary access to task metadata and adjacent service capabilities, increasing the chance of misuse, data exposure, or unauthorized actions if the agent follows these instructions in unrelated contexts.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
Allowing use of `beatra.tasks.list` to recover lost task IDs or inspect recent work from the current connection introduces access to broader historical task data that is not needed to generate one playlist. In a multi-user or reused session context, this can expose metadata about other tasks and encourage cross-request data access beyond least privilege.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The documentation includes detailed video-task billing and input/output video-second accounting despite the skill being only for office background music playlist creation. This mismatch is a strong sign of over-broad or copied capabilities, and it can cause the agent to invoke or reason about unrelated media-processing features, widening the attack surface and potentially exposing billing or usage data from capabilities outside the skill's intended scope.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The skill requests a very broad OAuth scope set including artifacts, images, videos, speech, voices, wallet spending, and task controls even though the skill is described as generating a simple coworking background-music playlist. This violates least privilege and gives any obtained token capabilities far beyond the skill's stated function, increasing the blast radius of misuse or compromise.

Context-Inappropriate Capability

Critical
Confidence
98% confidence
Finding
The code requests unrelated capabilities for image, video, speech generation, and voice read/write that do not match a low-stimulation office music playlist tool. Overbroad media and voice permissions create unnecessary opportunities for abuse, privacy impact, and lateral misuse of the user's account.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The code requests unrelated capabilities for image, video, speech generation, and voice read/write that do not match a low-stimulation office music playlist tool. Overbroad media and voice permissions create unnecessary opportunities for abuse, privacy impact, and lateral misuse of the user's account.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The skill detects and stores host platform information and device hostname in host.json, which creates a local fingerprint of the user's environment not clearly required for generating a playlist. While not immediately exfiltrated here, collecting extra environment metadata increases privacy risk and can aid profiling or targeting if the local state is later accessed.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill maintains a local inventory of installed skills and absolute install paths, which is unrelated to the declared playlist functionality and reveals details about the user's local environment. Those paths and package records can expose usage patterns and system layout, increasing privacy and reconnaissance risk if local state is read by another process or attacker.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
The file implements capabilities far beyond the declared playlist-generation purpose: credential handling, remote MCP sessions, generic tool invocation, telemetry registration, arbitrary file upload, and self-update with local file replacement. This scope mismatch is dangerous because users invoking a low-risk music skill would not reasonably expect broad remote-control and package-modification behavior, increasing the chance of covert data access or post-install capability expansion.

Context-Inappropriate Capability

High
Confidence
98% confidence
Finding
The upload() path reads any local regular file and sends it to a remote service after obtaining an upload grant. For a skill whose stated purpose is generating office background-music playlists, arbitrary local file exfiltration is unrelated and materially increases the risk of sensitive document, credential, or proprietary-data disclosure if the feature is triggered or abused.

Context-Inappropriate Capability

High
Confidence
97% confidence
Finding
The code performs autonomous discovery, download, validation, and replacement of installed package files, including a silent auto-update path. Even with checksum and path-safety checks, this gives a low-risk playlist skill an unnecessary self-modifying capability that can change behavior after installation and expand trust in the remote update channel beyond what users would expect.

Context-Inappropriate Capability

Medium
Confidence
95% confidence
Finding
The client exposes generic remote tool listing and invocation via tools/list and tools/call, allowing behavior far broader than playlist generation. In context, this undermines least privilege because the skill can act as a general-purpose proxy to remote capabilities that are not disclosed by the narrow skill description.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
This uninstall script handles shared device authorization state and decides when to revoke a remote OAuth/device credential, which is materially more privileged than the skill’s declared purpose of generating office music playlists. Even if framed as cleanup logic, embedding credential lifecycle management in an unrelated content skill expands the attack surface and gives the package influence over shared authentication used by other skills.

Context-Inappropriate Capability

Medium
Confidence
93% confidence
Finding
The code performs a network POST to a device revocation endpoint using a bearer token loaded from local state. For a playlist skill, outbound authorization-management traffic is out of scope and dangerous because any compromise, repurposing, or logic flaw in this path can disrupt account connectivity or be adapted for broader token misuse.

Missing User Warnings

Medium
Confidence
98% confidence
Finding
The skill states that new versions install automatically without separate confirmation, and this warning is buried rather than presented as a prominent user-facing consent event. Silent or weakly disclosed installation behavior is dangerous because users may unknowingly permit executable code changes after initial trust has been established, undermining informed consent and increasing supply-chain risk.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The document states that the client silently checks for updates and automatically installs a newer release by default without separate confirmation. Even with integrity checks, fixed endpoints, and rollback protections, modifying local installation files automatically expands the trust boundary and can surprise users or administrators, especially in controlled environments where unattended code changes are not acceptable.

Missing User Warnings

Medium
Confidence
88% confidence
Finding
The document describes automatic outbound installation registration and writes to a local cache file without any explicit user-facing notice or opt-in/opt-out guidance. Even though the data is framed as non-billable and non-secret, it still constitutes telemetry-like behavior and persistent local state creation, which can surprise users, leak environment metadata, and create compliance or trust issues in privacy-sensitive deployments.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The authorization flow asks for extensive privileged scopes but the console messaging only tells the user to open the approval page and select Allow, without enumerating the sensitive permissions being granted. This weakens informed consent and makes it easier for users to authorize capabilities they would not expect from a playlist skill.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
maybe_auto_update() performs silent, best-effort package updates during normal execution without presenting a user-facing warning at execution time. In a skill with an innocuous music-playlist description, this hidden modification behavior increases supply-chain and trust risks because code can change under the user without an explicit update action.

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
89% confidence
Finding
Referencing shared state files including credentials.json indicates the skill knows about and participates in handling credential-bearing material outside its functional domain. In the context of a music-playlist skill, access to credential storage is unnecessary and increases the risk of accidental exposure, deletion, or future malicious modification of authentication data.

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
This function reads access_token from credentials.json and uses it to authorize a remote revocation request. Direct token access by a skill is a serious boundary violation because bearer tokens are highly sensitive; if the package is altered or abused, the same code path could exfiltrate, reuse, or invalidate shared credentials.

Static analysis

No suspicious patterns detected.