Back to skill

Security audit

git-worktree-setup

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent worktree-setup purpose, but it should be reviewed because its templates can install persistent hooks and perform destructive file, process, and branch cleanup without strong safeguards.

Install only after reviewing the generated scripts and hook config. Avoid copying real secrets unless you understand where they will be duplicated, pin the installer version where possible, and require containment checks, backups, and confirmation before enabling automatic cleanup or any script that removes files, kills processes, or deletes branches.

Vulnerability Patterns
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (4)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/setup-worktree.sh:45
Finding

Existing Worktree Resources Are Recursively Deleted Before Symlink Creation

Content
View full analysis
$target" else echo " link $rel -> $target" fi mkdir -p "$(dirname "$dest")" ln -s "$target" "$dest" ``` ### Technical Analysis The `link_resource` helper deletes an existing destination recursively before replacing it with a symlink. This behavior is unsafe because: 1. Existing untracked files or directories are removed without backup or confirmation. 2. The `rel` argument is not validated against absolute paths or `..` path traversal. 3. The computed destination is not canonicalized and verified to remain inside `CURRENT_DIR`. 4. The script is intended to run automatically through session or worktree hooks, so deletion may occur without an immediately preceding user action. Shell quoting prevents ordinary argument splitting, but it does not provide path containment. A mistakenly or maliciously generated resource declaration could therefore make `dest` refer outside the intended worktree. The packaged declarations are static and benign, so exploitation depends on an unsafe declaration being generated or added when this template is customized. Nevertheless, the helper exposes a dangerous primitive to the agent-driven generation workflow. ### Attack Path 1. A repository contains misleading setup documentation, filenames, or other attacker-controlled content that influences the Skill's repository audit. 2. The agent classifies an attacker-selected path as a shared resource and passes it to `link_resource`. 3. The generated script is installed behind a `SessionStart` or worktree hook. 4. On invocation, `dest` resolves to an existing path, potentially outside the worktree if traversal was accepted. 5. `rm -rf "$dest"` recursively deletes that path. 6. The delet ...[truncated 467 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
references/recipes.md:217
Finding

Worktree Cleanup Recipe Trusts Unvalidated Paths, Ports, and Branches

Content
View full analysis
/dev/null ) || true # Kill any dev server holding ports we generated for this worktree. # Loops ALL hashed *_PORT keys, not just DEV_PORT. if [ -f "$WT/.env.local" ]; then for port in $(grep -E '^[A-Z_]+_PORT=' "$WT/.env.local" | cut -d= -f2); do [ -n "$port" ] && lsof -ti :"$port" 2>/dev/null | xargs kill 2>/dev/null || true done fi BRANCH=$(git -C "$WT" branch --show-current 2>/dev/null || true) git worktree remove "$WT" --force 2>/dev/null || true [ -n "$BRANCH" ] && git branch -D "$BRANCH" 2>/dev/null || true ``` ### Technical Analysis The cleanup recipe accepts `worktree_path` from hook JSON and treats it as authoritative. It does not verify that the path: - Is beneath the configured worktree root. - Is a registered worktree of the expected repository. - Is not the main worktree. - Refers to the worktree that triggered the hook. The recipe also reads values matching `*_PORT` from `.env.local` without validating them as numeric TCP/UDP port numbers. It then kills every process returned by `lsof` for those ports, without checking process ownership, executable identity, or association with the target worktree. Finally, `git worktree remove --force` can discard uncommitted work, and `git branch -D` force-deletes the associated branch without checking whether it has been merged or preserved remotely. This code is supplied as a recipe rather than an automatically installed script. The vulnerability becomes active when an agent follows the Skill's ...[truncated 1121 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
references/recipes.md:195
Finding

Worktree Creation Recipe Allows Path Traversal Through an Unvalidated Name

Content
View full analysis
/dev/tty 2>/dev/null || true; } log "Creating worktree on $BRANCH..." mkdir -p "$(dirname "$WT")" git worktree add -b "$BRANCH" "$WT" HEAD >/dev/null 2>&1 log "Bootstrapping resources..." ( cd "$WT" && bash "${REPO}/scripts/setup-worktree.sh" > /dev/tty 2>&1 ) || true echo "$WT" # ONLY the path on stdout ``` ### Technical Analysis The recipe interpolates the hook-supplied `name` directly into both a filesystem path and a Git branch name. It does not reject: - Absolute paths. - Slash-separated components. - `..` traversal. - Control characters. - Names that are invalid or ambiguous as Git references. Quoting protects the value from direct shell metacharacter execution, so this is not conventional shell command injection. However, quoting does not stop path traversal. A name containing traversal components can cause `WT` to resolve outside `${REPO}/.claude/worktrees`. The same untrusted value is used to construct `BRANCH`, creating additional reliability and integrity risks around Git reference handling. ### Attack Path 1. The recipe is installed as a `WorktreeCreate` hook. 2. The hook receives a crafted or malformed name containing path traversal components. 3. The script constructs `WT` by appending that name to the intended worktree root. 4. Filesystem resolution escapes the expected `.claude/worktrees` directory. 5. `git worktree add` creates a worktree at the unintended location if the resulting branch and path are accepted. 6. The bootstrap script then runs in that unintended worktree location. 7. A ...[truncated 470 chars]
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
README.md:31
Finding

Recommended Installation Executes an Unpinned npm Package

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
Findings (33)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description is for a meta-skill whose job is to inspect a repo and produce or update a setup-worktree script and hook configuration after planning. The supplied code is not such a generator/updater; it is the generated runtime script itself. Its primary purpose is to bootstrap a fresh worktree by linking, copying, and optionally generating environment settings. That is a materially different behavior and trigger surface: the description explicitly says the skill is not triggered when a new worktree is created, whereas this script is intended to run on SessionStart, WorktreeCreate, or manually. While the script is related to the declared domain, it performs undeclared operational actions and lacks the described audit/planning/generation behavior.

Content

No source excerpt is available for this finding.

Agent Config Directory Access

High
Category
Agent Snooping
Confidence
90% confidence
Finding

Skill reads from agent configuration directories (.claude/, .codex/, .gemini/). These directories may contain API keys, personal settings, and other credentials that the skill has no legitimate need to access.

Content

Scanner excerpt · assets/hook-config.json (reported line 2)May include surrounding context.

json
{
  "_comment": "Merge ONE of the blocks below into <repo>/.claude/settings.json -> hooks. SessionStart is the portable default; WorktreeCreate is cleaner if your team uses `claude --worktree`.",

  "_choice_a_session_start": {
    "_when": "Default. Works with manual `git worktree add`, IDE worktree creation, any agent CLI (Claude Code / Codex / Gemini). Runs after TUI renders so output mixes with banner — that's fine for setup logs.",

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 101)May include surrounding context.

md
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 107)May include surrounding context.

md
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 108)May include surrounding context.

md
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 129)May include surrounding context.

md
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 130)May include surrounding context.

md
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 230)May include surrounding context.

md
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 231)May include surrounding context.

md
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 111)May include surrounding context.

sh
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 143)May include surrounding context.

sh
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 150)May include surrounding context.

sh
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 151)May include surrounding context.

sh
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 152)May include surrounding context.

sh
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 153)May include surrounding context.

sh
PROJECT=$(clean_branch_name "$BRANCH")

# Per-worktree compose project name — avoids container/volume name collisions
upsert_env "$CURRENT_DIR/.env.local" COMPOSE_PROJECT_NAME "$PROJECT"

# CRITICAL: COMPOSE_PROJECT_NAME alone does NOT prevent host-port collisions.
# Two stacks both binding 0.0.0.0:5432 will fail with "address already in use".

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 123)May include surrounding context.

md
DEV_PORT=$(hash_port "$BRANCH")          # e.g. 4837 for branch "feat-auth"
API_PORT=$(hash_port "${BRANCH}-api")    # salt for second service

# WHICH .env file? Depends on the framework:
#   - Vite (apps/web)     → apps/web/.env.local           (reads VITE_PORT, PORT)
#   - Next.js (apps/web)  → apps/web/.env.local           (reads PORT)
#   - Compose vars        → root .env or .env.local       (interpolated by docker-compose)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 126)May include surrounding context.

md
DEV_PORT=$(hash_port "$BRANCH")          # e.g. 4837 for branch "feat-auth"
API_PORT=$(hash_port "${BRANCH}-api")    # salt for second service

# WHICH .env file? Depends on the framework:
#   - Vite (apps/web)     → apps/web/.env.local           (reads VITE_PORT, PORT)
#   - Next.js (apps/web)  → apps/web/.env.local           (reads PORT)
#   - Compose vars        → root .env or .env.local       (interpolated by docker-compose)

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 124)May include surrounding context.

md
API_PORT=$(hash_port "${BRANCH}-api")    # salt for second service

# WHICH .env file? Depends on the framework:
#   - Vite (apps/web)     → apps/web/.env.local           (reads VITE_PORT, PORT)
#   - Next.js (apps/web)  → apps/web/.env.local           (reads PORT)
#   - Compose vars        → root .env or .env.local       (interpolated by docker-compose)
#   - Bare Node script    → wherever your dev script reads

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 125)May include surrounding context.

md
API_PORT=$(hash_port "${BRANCH}-api")    # salt for second service

# WHICH .env file? Depends on the framework:
#   - Vite (apps/web)     → apps/web/.env.local           (reads VITE_PORT, PORT)
#   - Next.js (apps/web)  → apps/web/.env.local           (reads PORT)
#   - Compose vars        → root .env or .env.local       (interpolated by docker-compose)
#   - Bare Node script    → wherever your dev script reads

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 126)May include surrounding context.

md
API_PORT=$(hash_port "${BRANCH}-api")    # salt for second service

# WHICH .env file? Depends on the framework:
#   - Vite (apps/web)     → apps/web/.env.local           (reads VITE_PORT, PORT)
#   - Next.js (apps/web)  → apps/web/.env.local           (reads PORT)
#   - Compose vars        → root .env or .env.local       (interpolated by docker-compose)
#   - Bare Node script    → wherever your dev script reads

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 154)May include surrounding context.

sh
API_PORT=$(hash_port "${BRANCH}-api")    # salt for second service

# WHICH .env file? Depends on the framework:
#   - Vite (apps/web)     → apps/web/.env.local           (reads VITE_PORT, PORT)
#   - Next.js (apps/web)  → apps/web/.env.local           (reads PORT)
#   - Compose vars        → root .env or .env.local       (interpolated by docker-compose)
#   - Bare Node script    → wherever your dev script reads

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · references/recipes.md (reported line 131)May include surrounding context.

Use upsert_env so re-running updates in place instead of duplicating lines.

upsert_env "$CURRENT_DIR/apps/web/.env.local" PORT "$DEV_PORT" upsert_env "$CURRENT_DIR/apps/web/.env.local" VITE_PORT "$DEV_PORT" upsert_env "$CURRENT_DIR/apps/api/.env" PORT "$API_PORT"

text

---

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/setup-worktree.sh (reported line 142)May include surrounding context.

sh
# Use upsert_env so re-running updates in place instead of duplicating lines.
upsert_env "$CURRENT_DIR/apps/web/.env.local" PORT     "$DEV_PORT"
upsert_env "$CURRENT_DIR/apps/web/.env.local" VITE_PORT "$DEV_PORT"
upsert_env "$CURRENT_DIR/apps/api/.env"       PORT     "$API_PORT"
```

---

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The README describes bootstrapping worktrees by linking node_modules, copying .env, and generating setup scripts and hooks, but it does not prominently warn that the generated automation may duplicate sensitive local configuration and modify repository hook/script files. In a skill whose whole purpose is to inspect the repo and emit automation, missing disclosure increases the chance that users or downstream agents apply it without appreciating secret-handling and persistence implications.

Content

No source excerpt is available for this finding.

Rp1

Medium
Category
MCP Rug Pull
Confidence
70% confidence
Finding

npx commands without a version suffix (e.g. @1.0.0) create a rug-pull risk if the upstream server is compromised and publishes a malicious update.

Content

No source excerpt is available for this finding.