Back to skill

Security audit

stitch-prompt-card

Security checks for vulnerabilities and agentic risk

Overview

This skill appears purpose-built for TikTok quote-reply cards, but it asks for broad account powers and can silently replace its own installed code.

Review this before installing if you are uncomfortable granting a shared Beatra credential with broad media, wallet, artifact, and task permissions. Consider disabling automatic updates with the documented update --auto off command, only approve paid operations you understand, and revoke the Beatra device authorization from the console when you no longer use the skill.

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

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/authorize.py:31
Finding
Device authorization requests privileges unrelated to the declared Skill functionality<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:31-34` **Vulnerability Type**: Excessive OAuth scopes and violation of least privilege **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 declares a workflow for reading public TikTok posts and comments, uploading operator-selected assets, generating image cards, checking models and wallet information, and monitoring resulting tasks. The authorization scope is substantially broader than those requirements. It includes video generation, music generation, speech generation, voice creation, general wallet spending, and task cancellation. These capabilities are not necessary for the declared quote-card workflow. The resulting Device Token is shared across Beatra Skills and remains usable while active. Consequently, compromise or misuse of this token would grant access to unrelated paid and state-changing operations rather than only the minimum operations required by this package. ### Attack Path 1. The user runs `scripts/authorize.py`. 2. The authorization request asks the user to approve the complete scope string. 3. Beatra returns a bearer token containing the broad approved permissions. 4. The token is stored in `~/.beatra/credentials.json`. 5. A malicious instruction, compromised package update, or local process able to access the token invokes unrelated video, music, speech, voice, spending, or cancellation operations. 6. Those operations execute under the user's Beatra account despite being outside the declared purpose of this Skill. ### Impact Assessment An attacker who gains use of the credential can potentially: - Spend account credits on image, video, music, and speech operations. - Create or modify voice resources. - Read artifacts and tasks asso ...[truncated 286 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a package-specific least-privilege scope containing only the operations needed for: - TikTok video and comment lookup. - Asset upload. - Text-to-image model discovery and generation. - Task reads. - Read-only wallet and billing access, if required. 2. Remove video, music, speech, voice-write, and task-cancellation scopes unless a documented workflow explicitly requires them. 3. Separate read-only, billable, and administrative capabilities into different tokens or grants. 4. Display the exact requested capabilities to the user before opening the authorization page. 5. Avoid sharing a full-scope token between unrelated Skills. Prefer package-bound credentials enforced by the server. 6. Add server-side authorization policies that reject tools outside the package's registered allowlist, even if a broader token is presented. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/mcp_client.py:1480
Finding
Generic MCP dispatcher permits arbitrary authenticated tool invocation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:1480-1500`, `scripts/mcp_client.py:1510-1512` **Vulnerability Type**: Missing tool allowlist on a privileged authenticated dispatcher **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}, ) ``` ```python call = subparsers.add_parser("call", help="Call one tool with a JSON object on stdin") call.add_argument("tool_name") ``` ### Technical Analysis The command-line interface accepts an unrestricted `tool_name` and sends it directly to the remote MCP endpoint. No local allowlist limits calls to the operations documented for this Skill. This is particularly dangerous because the dispatcher authenticates requests using the broad Device Token stored in `~/.beatra/credentials.json`. The Skill documentation limits normal behavior, but documentation is not a security boundary. An Agent affected by prompt injection, operator error, or malicious future package instructions can call any tool accepted by the remote service and authorized by the token. Although arguments must be supplied as a JSON object through standard input, that validation does not constrain the selected tool or its security impact. ### Attack Path 1. An attacker influences the Agent through malicious ...[truncated 964 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Add a fixed local allowlist of tool names required by this package. 2. Reject every tool not explicitly present in the allowlist before creating an authenticated session. 3. Apply per-tool argument validation rather than accepting any JSON object. 4. Separate non-billable reads from billable and destructive operations. 5. Require explicit, operation-specific confirmation before billable calls. 6. Enforce the same package-to-tool allowlist on the server; client-side checks alone are insufficient. 7. Avoid exposing a generic `call <tool_name>` interface in a narrowly scoped Skill. Use dedicated subcommands for each approved operation. ]]>

T03 · Remote Payload Retrieval and Execution

Error
Location
scripts/mcp_client.py:999
Finding
Silent default-on updater retrieves and replaces executable package code<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:532-539`, `scripts/mcp_client.py:999-1047`, `scripts/mcp_client.py:1528-1530` **Vulnerability Type**: Remote payload retrieval and automatic executable replacement **Risk Level**: High ### Vulnerable Code ```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 ``` ```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 ...[truncated 3280 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Disable automatic updates by default. 2. Require explicit user confirmation after displaying the source, version, release notes, and affected files. 3. Sign discovery metadata and release manifests with an offline-controlled asymmetric key. 4. Embed or securely provision the verification public key independently of the update servers. 5. Reject unsigned releases even when HTTPS and hashes are valid. 6. Separate discovery, signing, and payload-hosting authority so compromise of one service is insufficient. 7. Consider delegating updates to the host package manager, which can provide review, rollback, and provenance controls. 8. Preserve the existing archive path confinement, ownership checks, resource limits, transaction journal, and rollback protections. ]]>

other

Note
Location
scripts/authorize.py:340
Finding
Authorization and registration collect persistent host and Agent-environment metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:340-381`, `scripts/authorize.py:455-470`; `scripts/mcp_client.py:1160-1181`, `scripts/mcp_client.py:1348-1363` **Vulnerability Type**: Environment reconnaissance and persistent installation telemetry **Risk Level**: Low ### Vulnerable Code ```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] ``` ```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_platfor ...[truncated 2006 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Make hostname and installation telemetry explicitly opt-in. 2. Omit `device_name` from authorization unless the user chooses to provide one. 3. Use a user-selected display name rather than the system hostname. 4. Replace the stable installation reference with a rotating or package-scoped pseudonymous identifier where possible. 5. Do not attach source-platform telemetry to every business request unless required for security or billing. 6. Provide a documented setting to disable registration and source attribution independently of core functionality. 7. Define retention, access, and deletion policies for collected telemetry. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/mcp_client.py:1074
Finding
Windows credential confidentiality relies on unverified inherited ACLs<![CDATA[ ## Vulnerability Details **File Location**: `scripts/authorize.py:121-134`, `scripts/mcp_client.py:1074-1081` **Vulnerability Type**: Missing credential-file access-control enforcement on Windows **Risk Level**: Medium ### Vulnerable Code ```python def _private_directory(path: Path) -> None: # POSIX gets explicit 700/600. On Windows the state directory lives under # the user profile, whose default ACL is already private to the user — # the same posture as gh/aws/gcloud credential stores. The former custom # DACL ceremony was dropped deliberately: its command patterns read as # hostile to agent safety policies and endpoint security, failing installs # while adding no protection an elevated administrator could not bypass. path.mkdir(mode=0o700, parents=True, exist_ok=True) if os.name == "posix": path.chmod(0o700) def _restrict_file(path: Path) -> None: if os.name == "posix": path.chmod(0o600) ``` ```python def _read_private_credentials(state_dir: Path, path: Path) -> str: if os.name == "nt": # The state directory lives under the user profile, whose default # ACL is already private to the user (the gh/aws/gcloud posture). # The former custom DACL verification was dropped deliberately: its # command patterns read as hostile to agent safety policies and # endpoint security, failing installs while adding nothing an # elevated administrator could not bypass. return path.read_text(encoding="utf-8") ``` ### Technical Analysis On POSIX systems, the implementation explicitly applies and verifies a `0700` state-directory mode, a `0600` credential-file mode, user ownership, regular-file status, and no-follow file opening. On Windows, the implementation assumes that the user's profile ACL is private. It neither creates a restricted discretionary access-control list nor verifies the effective ACL before reading the Device Token. Profile inheritance ...[truncated 1195 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Store the Device Token in Windows Credential Manager or another operating-system secret store. 2. If a file must be used, create a protected directory and file with inheritance disabled and access limited to: - The current user. - `SYSTEM`, if operationally required. 3. Verify the effective ACL before every credential read and reject unsafe configurations. 4. Avoid shelling out to ACL tools; use supported Windows security APIs or a narrowly reviewed library. 5. Detect reparse points and non-regular files before opening the credential. 6. Update the documentation so its guarantees exactly match the implemented controls. 7. Add tests covering shared profiles, modified parent ACLs, reparse points, and credential files created by older versions. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (15)

Lp3

Medium
Category
MCP Least Privilege
Confidence
95% confidence
Finding
The skill exercises broad capabilities including shell, network, file read/write, and environment access without any declared permissions or clear upfront consent boundary. That makes it harder for operators and host systems to reason about trust, increases the chance of over-privileged execution, and creates room for unintended data access or command execution through the bundled client flow.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding
The declared function is limited to generating TikTok quote-reply cards, but the skill also performs authentication, persistent credential storage, telemetry/registration, generic remote tool invocation, file upload, uninstall cleanup, and automatic self-update. This mismatch is dangerous because users may authorize a seemingly narrow media workflow while unknowingly granting a much broader execution and persistence surface, including remote code and data handling behaviors.

Description-Behavior Mismatch

High
Confidence
99% confidence
Finding
The authorization flow requests an extremely broad OAuth scope set, including artifacts, image/video/music/speech generation, voice management, task control, and wallet spending, despite the skill being described as a TikTok stitch prompt card tool. This violates least privilege and creates unnecessary account and financial exposure if the credential is later abused, leaked, or reused by other components.

Context-Inappropriate Capability

High
Confidence
99% confidence
Finding
Requesting wallet spending plus voice/music/task capabilities for a stitch prompt card skill is unjustified by the stated purpose and materially increases blast radius. Even if the code only stores the token locally, any compromise of that token or downstream misuse could enable charges, broader data access, or invocation of unrelated privileged services.

Description-Behavior Mismatch

High
Confidence
94% confidence
Finding
The file contains extensive self-update and package replacement logic unrelated to the stated TikTok card-generation purpose. Even though it includes integrity checks, it downloads code from remote infrastructure and replaces installed package files, creating a substantial supply-chain and post-install code-execution surface that exceeds user expectations for this skill.

Description-Behavior Mismatch

Medium
Confidence
87% confidence
Finding
The code records local skill inventory and sends installation registration telemetry that is not necessary for generating quote-reply cards. This expands data collection beyond the declared purpose and may expose local environment details or usage metadata without clear user awareness.

Context-Inappropriate Capability

Medium
Confidence
90% confidence
Finding
The skill fingerprints the host agent platform using environment variables and a local host file, which is not clearly justified by its creative media function. Such environment identification can be used for profiling, targeting behavior by host, or tailoring follow-on actions in ways the user does not expect.

Context-Inappropriate Capability

Medium
Confidence
85% confidence
Finding
The client silently injects source_package_slug and source_platform into tool-call arguments for every business call. This adds tracking metadata unrelated to the declared creative task and can leak contextual information to the remote service beyond what the user explicitly provided.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill states that the bundled client silently auto-updates and installs newer releases without separate confirmation. Even with verification claims, silent code replacement materially changes the trust model after installation and can introduce new behavior, new permissions, or supply-chain risk without an explicit user decision at execution time.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The manifest advertises reading TikTok video/comments and configures an authenticated remote MCP service, but the user-facing description does not disclose that content will be fetched over the network or that account-backed credentials may be used. This creates a transparency and consent gap: users may supply URLs or invoke the skill without realizing external requests and authenticated data access are occurring.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The manifest declares use of a local credential file for device-bearer authentication without any user-visible notice in the metadata. Even if the platform normally supports credentials, silently depending on local authentication material increases the risk of surprising privilege use and undermines informed consent.

Missing User Warnings

Medium
Confidence
89% confidence
Finding
The document states that the client silently checks for and automatically installs newer releases without separate confirmation. Even though the text describes multiple integrity protections, automatic modification of locally installed code without an explicit per-update prompt increases supply-chain and user-consent risk because a compromised update pipeline or mistaken release could change executable behavior before the user notices.

Missing User Warnings

Medium
Confidence
84% confidence
Finding
The document states that the client automatically performs a network registration call on first use and sends package slug, version, platform, and a stable external installation reference, but it does not describe an explicit user-facing notice or consent step. Even if the data is described as non-secret and non-billable, silent telemetry-like transmission can expose deployment metadata and create privacy, compliance, or policy issues in environments that restrict outbound calls.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The skill performs silent automatic updates that can modify installed package files before handling normal commands, without prompting the user at the moment of change. In the context of a TikTok card-generation skill, this is especially risky because it introduces hidden code changes unrelated to the core creative function and increases supply-chain abuse impact.

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
95% confidence
Finding
The exposed self-update command enables the package to replace its own installed code. Self-modification is dangerous in a third-party skill because it can bypass normal review expectations, amplify compromise of the update channel, and change behavior after installation in ways unrelated to the declared TikTok media workflow.

Static analysis

No suspicious patterns detected.