T03 · Remote Payload Retrieval and Execution
- Location
actions/deploy-skill.sh:19- Finding
Attacker-Supplied Remote Archive Is Downloaded and Automatically Executed
- Content
View full analysis
&2 exit 2 fi if [ -z "$SHA_EXPECT" ]; then echo "sha is required and must be sha256" | tee -a "$LOG" >&2 exit 2 fi if [[ ! "$SHA_EXPECT" =~ ^[a-fA-F0-9]{64}$ ]]; then echo "sha must be a 64-char hex digest" | tee -a "$LOG" >&2 exit 2 fi if [ "${OPENCLAW_ALLOW_DEPLOY_SKILL:-0}" != "1" ]; then echo "deploy-skill disabled: set OPENCLAW_ALLOW_DEPLOY_SKILL=1" | tee -a "$LOG" >&2 exit 3 fi TMP_DIR="/tmp/${TASK_ID}" mkdir -p "$TMP_DIR" ARCHIVE="$TMP_DIR/artifact.tar.gz" echo "Downloading $URL" | tee -a "$LOG" curl -fsSL "$URL" -o "$ARCHIVE" if command -v sha256sum >/dev/null 2>&1; then SHA_ACT=$(sha256sum "$ARCHIVE" | awk '{print $1}') else SHA_ACT=$(shasum -a 256 "$ARCHIVE" | awk '{print $1}') fi if [ "$SHA_EXPECT" != "$SHA_ACT" ]; then echo "SHA mismatch expected=$SHA_EXPECT actual=$SHA_ACT" | tee -a "$LOG" >&2 exit 4 fi DEST="/opt/openclaw/skills/$NAME" mkdir -p "$DEST" echo "Extracting into $DEST" | tee -a "$LOG" tar -xzf "$ARCHIVE" -C "$DEST" if [ -x "$DEST/test_smoke.sh" ]; then echo "Running smoke test" | tee -a "$LOG" (cd "$DEST" && ./test_smoke.sh) || { echo "Smoke failed" | tee -a "$LOG" >&2; exit 5; } fi ``` ### Technical Analysis The deployment task controls both `params.artifact_url` and `params.sha`. The script only requires an HTTPS URL and a syntactically valid SHA-256 digest. Because the expected digest is supplied by the same untrusted task as the archive URL, it provides transfer-integrity checking but no publisher authentication. An attacker can therefore host an arbitrary archive, calculate its SHA-256 digest, and provide both values. After verification, the archive is extracted into the persistent Skill directory. If it c ...[truncated 1554 chars]- Remediation
View remediation
