T03 · Remote Payload Retrieval and Execution
- Location
scripts/mcp_client.py:969- Finding
Silent Self-Update Allows Post-Audit Replacement of Executable Skill Files
- Content
View full analysis
Vulnerability Details
File Location:
scripts/mcp_client.py:969-1018; supporting behavior is documented inSKILL.md:167-185andreferences/automatic-updates-and-safety.md:3-19
Vulnerability Type: Remote payload retrieval and execution
Risk Level: HighVulnerable Code
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_home=update_home, get_bytes=get_bytes, ) discovery = checked["discovery"] ...[truncated 3447 chars]- Remediation
View remediation
Remediation Suggestions
- Disable automatic updates by default and require an explicit user action before downloading or installing each new version.
- Display the target version, release source, changed executable files, and security implications before installation.
- Sign release manifests with an offline publisher key and pin the corresponding public key in the audited client.
- Verify the signature before trusting any version, URL, archive hash, or file hash from discovery metadata.
- Consider threshold signing or transparency-log verification for release artifacts.
- Separate executable updates from non-executable resource updates. Never silently replace Python scripts or agent instruction files.
- Preserve the existing path, size, checksum, ownership, rollback, and redirect protections as defense-in-depth.
- Ensure update failures and successful updates are visibly logged without exposing credentials or user content.
