T03 · Remote Payload Retrieval and Execution
- Location
- scripts/mcp_client.py:969
- Finding
- Silent automatic replacement of executable Skill code from a remote release channel<![CDATA[ ## Vulnerability Details **File Location**: `scripts/mcp_client.py:520-522`, `scripts/mcp_client.py:969-1015`, `scripts/mcp_client.py:1541-1544` **Vulnerability Type**: Remote payload retrieval and execution **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 = check_update(get_b ...[truncated 3160 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Disable automatic installation by default. Missing or invalid update state should resolve to `"auto_update": false`. 2. Make update checks read-only unless the user explicitly requests installation. 3. Display the proposed version, source, and changed files, and require informed confirmation before replacement. 4. Sign release metadata and archives with a dedicated release key. Verify the signature using an embedded public key independent of the downloaded discovery document. 5. Apply key rotation through a separately authenticated process rather than trusting replacement package content to introduce arbitrary keys. 6. Consider distributing updates through the host platform's reviewed package mechanism instead of implementing mutable self-update behavior. 7. Preserve the existing path, ownership, size, rollback, and checksum defenses as defense-in-depth. ]]>
