T09 · Insecure Skill Coding Practices
- Location
scripts/local-to-staging-pr.sh:120- Finding
Forced deletion of unrelated dirty worktrees without confirmation
- Content
View full analysis
Vulnerability Details
File Location:
scripts/local-to-staging-pr.sh, lines 120–134
Vulnerability Type: Unchecked destructive cleanup of unrelated Git worktrees
Risk Level: MediumTechnical Analysis
Before creating a staging worktree, the script enumerates all registered worktrees beneath the repository's
.claude/worktrees/directory. If a worktree's branch is an ancestor oforigin/main, it forcibly removes that worktree and forcibly deletes its branch:bash while IFS= read -r wt_path; do [[ -z "$wt_path" || "$wt_path" != "$REPO"/.claude/worktrees/* ]] && continue wt_branch=$(git -C "$wt_path" branch --show-current 2>/dev/null || true) [[ -z "$wt_branch" ]] && continue if git merge-base --is-ancestor "$wt_branch" origin/main 2>/dev/null; then echo "Reclaiming already-merged worktree: $wt_path ($wt_branch)" >&2 git worktree remove "$wt_path" --force 2>/dev/null || true git branch -D "$wt_branch" 2>/dev/null || true fi done < <(git worktree list --porcelain | awk '/^worktree /{print $2}')The ancestry test establishes only that the branch's committed history is reachable from
origin/main. It does not establish that the worktree is clean or inactive. The code does not rungit status --porcelain, inspect Git operation indicators such asMERGE_HEAD,CHERRY_PICK_HEAD, or rebase state, or request confirmation before usinggit worktree remove --force.Consequently, the authorization to prepare one staging PR is expanded into destructive cleanup of separate workspaces. Those workspaces may contain uncommitted tracked changes, untracked files, or an in-progress Git operation belonging to another session or user workflow.
The documentation at
worktree.md:217describes the automatic reclamation as safe, but the executable path does not enforce the cleanliness and operation-state gates documented elsewhere in the Skill.Attack Path
- Another session, edit ...[truncated 1360 chars]
- Remediation
View remediation
Remediation Suggestions
Remove opportunistic deletion of unrelated worktrees from the staging-PR helper, or place it behind a dedicated explicit cleanup flag and per-worktree confirmation.
Before any worktree removal, enforce all of the following:
- Resolve the worktree's absolute Git directory and reject removal if operation indicators such as
CHERRY_PICK_HEAD,MERGE_HEAD,REBASE_HEAD,BISECT_LOG,rebase-merge, orrebase-applyexist. - Run
git -C "$wt_path" status --porcelainand skip the worktree unless the output is empty. - Verify that the candidate is not the primary worktree and that its path is within the intended canonical worktree directory.
- Present the exact worktree path and branch to the user and require explicit confirmation before deletion.
- Use non-forced
git worktree remove "$wt_path"so Git's own safety checks remain effective. - Delete the branch only after successful worktree removal, and prefer
git branch -dovergit branch -D. - Log skipped dirty or mid-operation worktrees rather than suppressing errors with
2>/dev/null || true.
A safer design is to leave cleanup entirely to the existing dry-run-first worktree-pruning workflow and keep this helper focused solely on creating the requested staging worktree.
- Resolve the worktree's absolute Git directory and reject removal if operation indicators such as
