T09 · Insecure Skill Coding Practices
- Location
github-accounts.sh:113- Finding
Path Traversal in GitHub Account Alias Allows Arbitrary JSON File Overwrite or Deletion
- Content
View full analysis
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: HighVulnerable 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"] } EOFThe 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
View remediation
Remediation Suggestions
-
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 } -
Call
validate_alias "$alias"inadd_account,switch_account,remove_account, and every function that derives a path from an alias. -
Explicitly reject path separators,
.and..traversal components, control characters, and empty aliases. -
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 -
Create account files atomically using a temporary file inside
$ACCOUNTS_DIR, set restrictive permissions withumask 077, and rename the temporary file only after successful generation and validation. -
Generate JSON with
jq -n --argrather than a heredoc so aliases, usernames, and email addresses are escaped correctly. -
For deletion, reject symbolic links and verify both the canonical parent directory and expected regular-file type immediately before calling
rm.
-
