T03 · Remote Payload Retrieval and Execution
Error
- Location
- SKILL.md:52
- Finding
- Mandatory Silent Remote Code Update and Immediate Activation<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:52-64`; `scripts/check_update.py:104-106, 138-140, 187-250` **Vulnerability Type**: Remote payload retrieval and execution **Risk Level**: Critical ### Vulnerable Code `SKILL.md:52-64`: ```markdown **Step 0 — Check for skill updates (silent, once per day).** Before anything else, run: ```bash python scripts/check_update.py ``` The script self-throttles to one real check per 24 hours (via a `.last_update_check` timestamp in the skill root); running it every session is cheap. It always exits 0 and never fails the workflow — route on `data.action` only when you need to tell the user something: - **`updated`** → one line: `[Skill updated: <from> → <to> (<commits_behind> commits). Continuing with new version.]`. - **`skipped_dirty`** → one line notifying the user that the update was skipped. - Everything else (`up_to_date`, `skipped_throttled`, `skipped_disabled`, `not_a_git_repo`, `check_failed`) → continue silently. ``` `scripts/check_update.py:104-106, 138-140`: ```python def fetch() -> tuple[bool, str]: rc, _, stderr = run_git("fetch", "--quiet", "origin") return rc == 0, stderr def fast_forward() -> tuple[bool, str]: rc, _, stderr = run_git("pull", "--ff-only", "--quiet") return rc == 0, stderr ``` `scripts/check_update.py:187-250`: ```python # One network call: fetch objects so we can diff locally afterwards. fetched, fetch_err = fetch() if not fetched: ok({"action": "check_failed", "reason": (f"git fetch failed: " f"{fetch_err.splitlines()[0] if fetch_err else 'unknown error'}"), "local_head": local[:12]}) return upstream = upstream_head() if not upstream: ok({"action": "check_failed", "reason": ("No upstream tracking branch configured " "(e.g. 'git branch --set-upstream-to=origin/main')"), "local_head": local[:12]}) return if local == upstream: ok({"action": "up_to_date", "head" ...[truncated 3891 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Remove automatic update installation from normal Skill activation. 2. Replace `git pull` with a non-mutating availability check. 3. Display the repository URL, current commit, proposed commit, and change summary before any update. 4. Require explicit user approval before modifying the installed Skill. 5. Pin approved releases to immutable commit hashes or signed tags. 6. Verify commit or tag signatures against a bundled allowlist of maintainer keys. 7. Validate that `origin` exactly matches an approved canonical repository before contacting it. 8. Install updates into a staging directory and audit them before activation. 9. Activate updated code only in a new session or process after review. 10. Default to update checks being disabled for package-manager installations and provide a clearly documented opt-in mechanism. 11. Preserve `SCHOLAR_SKIP_UPDATE_CHECK`, but do not rely on an opt-out variable as the primary security control. ]]>
