T09 · Insecure Skill Coding Practices
Error
- Location
- github-accounts.sh:113
- Finding
- Path Traversal in GitHub Account Alias Allows Arbitrary JSON File Overwrite or Deletion## Vulnerability Details **File Location**: `github-accounts.sh`, lines 113-143, 209-250, and 269-286 **Vulnerability Type**: Path traversal through an unvalidated filename component **Risk Level**: High ### Vulnerable Code Account switching constructs a path directly from the caller-controlled alias: ```bash local config_file="$ACCOUNTS_DIR/${alias}.json" if [[ ! -f "$config_file" ]]; then echo -e "${YELLOW}⚠️ 账户配置不存在,需要重新认证${NC}" echo "" # 保存当前账户 local current=$(get_current_account) echo "$current" > "$ACCOUNTS_DIR/.backup_current" # 退出当前认证 gh auth logout -y 2>/dev/null || true # 重新认证 gh auth login --hostname github.com --git-protocol https # 保存配置 local user=$(gh api user --jq .login 2>/dev/null) local email=$(gh api user --jq .email 2>/dev/null || echo "private") cat > "$config_file" << EOF { "alias": "${alias}", "username": "${user}", "email": "${email}", "hostname": "github.com", "protocol": "https", "authedAt": "$(date -Iseconds)", "scopes": ["repo", "user", "workflow"] } EOF ``` The same unsafe construction is used when adding an account: ```bash local config_file="$ACCOUNTS_DIR/${alias}.json" if [[ -f "$config_file" ]]; then echo -e "${YELLOW}⚠️ 账户 ${alias} 已存在${NC}" echo "" echo -e "${CYAN}当前配置:${NC}" cat "$config_file" echo "" read -p "是否覆盖?(y/N) " -n 1 -r echo "" if [[ ! $REPLY =~ ^[Yy]$ ]]; then exit 0 fi fi # 保存当前账户 local current=$(get_current_account) echo "$current" > "$ACCOUNTS_DIR/.backup_current" # 退出当前认证 gh auth logout -y 2>/dev/null || true # 交互式认证 echo -e "${YELLOW}📝 开始认证流程...${NC}" echo "" gh auth login --hostname github.com --git-protocol https # 获取用户信息 local user=$(gh api user --jq .login 2>/dev/null) local email=$(gh api user --jq .email 2>/dev/null || echo "private") # 保存配置 cat > "$config_f ...[truncated 3576 chars]
- Remediation
- ## Remediation Suggestions 1. Enforce a strict allowlist for aliases before constructing any path: ```bash validate_alias() { local alias="$1" if [[ ! "$alias" =~ ^[A-Za-z0-9_-]+$ ]]; then echo "Invalid account alias" >&2 exit 1 fi } ``` 2. Call `validate_alias "$alias"` in `add_account`, `switch_account`, `remove_account`, and every function that derives a path from an alias. 3. Explicitly reject path separators, `.` and `..` traversal components, control characters, and empty aliases. 4. Canonicalize and verify the destination before writing or deleting: ```bash accounts_root=$(realpath -m "$ACCOUNTS_DIR") config_file=$(realpath -m "$ACCOUNTS_DIR/${alias}.json") case "$config_file" in "$accounts_root"/*.json) ;; *) echo "Resolved path is outside the account directory" >&2 exit 1 ;; esac ``` 5. Create account files atomically using a temporary file inside `$ACCOUNTS_DIR`, set restrictive permissions with `umask 077`, and rename the temporary file only after successful generation and validation. 6. Generate JSON with `jq -n --arg` rather than a heredoc so aliases, usernames, and email addresses are escaped correctly. 7. For deletion, reject symbolic links and verify both the canonical parent directory and expected regular-file type immediately before calling `rm`.
