T03 · Remote Payload Retrieval and Execution
Error
- Location
- scripts/mcp_update.sh:23
- Finding
- Scheduled updater retrieves and executes a mutable remote container image<![CDATA[ ## Vulnerability Details **File Location**: `docker-compose.yml:3`; `scripts/mcp_update.sh:8, 23-53`; `scripts/cron_install.sh:82-103` **Vulnerability Type**: Mutable remote payload retrieval and automatic execution **Risk Level**: High ### Vulnerable Code ```yaml # docker-compose.yml:1-6 services: autotask-mcp: image: ghcr.io/asachs01/autotask-mcp:latest container_name: autotask-mcp env_file: - .env ``` ```bash # scripts/mcp_update.sh:8 IMAGE="ghcr.io/asachs01/autotask-mcp:latest" ``` ```bash # scripts/mcp_update.sh:23-53 docker compose pull 2>&1 | tee -a "$LOGFILE" # Capture new image digest after pull NEW_DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE" 2>/dev/null || echo "unknown") log "Pulled digest: ${NEW_DIGEST}" # --- Supply chain verification --- # If a pinned digest file exists, verify the pulled image matches it. # Users can pin a known-good digest by running: # ./scripts/mcp_pin_digest.sh if [[ -f "$DIGEST_FILE" ]]; then PINNED=$(< "$DIGEST_FILE") # Extract just the sha256:... portion from the full repo@sha256:... string PULLED_SHA="${NEW_DIGEST##*@}" if [[ "$PULLED_SHA" != "$PINNED" ]]; then log "WARNING: Pulled image digest does NOT match pinned digest!" log " Pinned : ${PINNED}" log " Pulled : ${PULLED_SHA}" log "Refusing to restart. Review the new image and update the pin with:" log " ./scripts/mcp_pin_digest.sh" exit 1 fi log "Digest matches pin: ${PINNED}" fi if [[ "$OLD_DIGEST" != "$NEW_DIGEST" ]]; then log "New image detected." log "Recreating container with updated image..." docker compose up -d 2>&1 | tee -a "$LOGFILE" log "Update complete." else log "Already on latest image. No restart needed." fi ``` ```ini # Generated by scripts/cron_install.sh:80-88 [Unit] Description=Autotask MCP Docker image update [Service] Type=oneshot ExecStart=${SCRIPT_PATH} WorkingDirectory=${SKILL_DIR} ``` ### Technical Analysis The Compose configu ...[truncated 2997 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace the mutable Compose reference with an immutable reviewed digest: ```yaml image: ghcr.io/asachs01/autotask-mcp@sha256:<reviewed-digest> ``` 2. Make verification fail closed. The updater should refuse to pull or start an update when `.pinned-digest` is absent, malformed, or cannot be read. 3. Validate pinned values against a strict format such as `^sha256:[0-9a-f]{64}$`. 4. Do not update the pin automatically from the current `latest` image. Require a separate review and approval workflow before changing the trusted digest. 5. Prefer signature and provenance verification, such as Sigstore/Cosign verification against an explicitly trusted identity, in addition to digest pinning. 6. Separate retrieval from deployment: pull and inspect a candidate image first, then require explicit approval before replacing the running container. 7. If unattended updates remain supported, restrict them to signed release tags and document that enabling the timer authorizes recurring retrieval and execution of upstream code. 8. Use narrowly scoped Autotask credentials with only the permissions needed for the intended MCP operations, and rotate them immediately if an untrusted image may have run. ]]>
