Back to skill

Security audit

Github

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate GitHub automation skill, but it can change repositories and GitHub login state with weak safeguards and has implementation flaws that users should review before installing.

Install only if you trust this skill to act on your GitHub repositories with your current gh identity. Use dry-run modes where available, avoid untrusted account aliases or notification content, review branch cleanup targets before running, and be aware that account add/switch may log out your current GitHub CLI session and notifications may send repo metadata to external chat services.

Vulnerability Patterns
  • 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
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (2)

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

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: 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
View 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" >&amp;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" >&amp;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.

T09 · Insecure Skill Coding Practices

Warning
Location
github-notify.sh:116
Finding

Unescaped Notification Fields Permit JSON Payload Injection

Content
View full analysis

Vulnerability Details

File Location: github-notify.sh, lines 116-129, 151-160, and 205-217
Vulnerability Type: JSON injection caused by unsafe string interpolation
Risk Level: Medium

Vulnerable Code

Discord payload construction:

bash
local payload=$(cat << EOF
{
  "content": "",
  "embeds": [
    {
      "title": "${title}",
      "description": "${description}",
      "color": ${color},
      "thumbnail": {
        "url": "${icon:-https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png}"
      }
    }
  ]
}
EOF
)

DingTalk payload construction:

bash
local payload=$(cat << EOF
{
  "msgtype": "markdown",
  "markdown": {
    "title": "${title}",
    "text": "### ${title}\n${description}\n\n---\n发送时间: $(date '+%Y-%m-%d %H:%M:%S')"
  }
}
EOF
)

Slack payload construction:

bash
local payload=$(cat << EOF
{
  "attachments": [
    {
      "title": "${title}",
      "text": "${description}",
      "color": "${color}",
      "footer": "GitHub Notifications",
      "ts": "$(date +%s)"
    }
  ]
}
EOF
)

The generated payload is sent directly to the configured webhook:

bash
curl -s -X POST \
    -H "Content-Type: application/json" \
    -d "$payload" \
    "$webhook_url" > /dev/null 2>&amp;1

Technical Analysis

Notification values derived from command-line arguments or a caller-selected file are interpolated directly into JSON heredocs. The affected fields include the title, description, color, and icon URL.

JSON strings require escaping for quotation marks, backslashes, carriage returns, line feeds, and other control characters. Shell quoting around "$payload" only preserves the assembled string when invoking curl; it does not make the interpolated content valid or safe JSON.

For example, a title containing a quotation mark can terminate the intended JSON string. ...[truncated 2927 chars]

Remediation
View remediation

Remediation Suggestions

  1. Construct JSON with jq instead of interpolating values into heredocs. For example:

    bash
    payload=$(jq -n \
        --arg title "$title" \
        --arg description "$description" \
        --arg icon "${icon:-https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png}" \
        --argjson color "$color" \
        '{
          content: "",
          embeds: [{
            title: $title,
            description: $description,
            color: $color,
            thumbnail: {url: $icon}
          }]
        }')
    
  2. Validate Discord colors as decimal integers within the platform-supported range before passing them to --argjson:

    bash
    if [[ ! "$color" =~ ^[0-9]+$ ]] || (( color &lt; 0 || color &gt; 16777215 )); then
        echo "Invalid Discord color" >&amp;2
        exit 1
    fi
    
  3. Use jq -n --arg for every string in the Discord, DingTalk, and Slack payloads. Do not manually escape JSON with sed or string replacement.

  4. Validate icon URLs against an explicit https policy if arbitrary remote images are not required.

  5. Consider restricting or neutralizing mass-mention syntax when notification text can originate from untrusted users.

  6. Make HTTP failures visible:

    bash
    curl --fail-with-body --silent --show-error \
        -X POST \
        -H "Content-Type: application/json" \
        --data-binary "$payload" \
        "$webhook_url"
    
  7. Report success only after curl returns successfully and the destination provides an acceptable HTTP status.

Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The documented feature set understates destructive repository actions such as deleting remote branches or modifying PR labels. Users invoking a seemingly general GitHub assistant may not expect destructive mutations, which creates a real risk of accidental data loss or unauthorized repository changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The documented feature set understates destructive repository actions such as deleting remote branches or modifying PR labels. Users invoking a seemingly general GitHub assistant may not expect destructive mutations, which creates a real risk of accidental data loss or unauthorized repository changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

The documented feature set understates destructive repository actions such as deleting remote branches or modifying PR labels. Users invoking a seemingly general GitHub assistant may not expect destructive mutations, which creates a real risk of accidental data loss or unauthorized repository changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding

The documented feature set understates destructive repository actions such as deleting remote branches or modifying PR labels. Users invoking a seemingly general GitHub assistant may not expect destructive mutations, which creates a real risk of accidental data loss or unauthorized repository changes.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

The documented feature set understates destructive repository actions such as deleting remote branches or modifying PR labels. Users invoking a seemingly general GitHub assistant may not expect destructive mutations, which creates a real risk of accidental data loss or unauthorized repository changes.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill documentation advertises shell-based operational workflows but does not declare any tool scope such as permissions or allowed-tools. In an agent ecosystem, missing scope declarations can cause reviewers or users to underestimate the skill's ability to run local commands and modify repository state, increasing the chance of unsafe execution.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The skill description and all user-facing documentation are presented exclusively in Chinese, with no indication that users can choose another language or that the locale restriction is intentional and justified. This can violate language/locale policy when a specific language is effectively forced without opt-in.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

Force-push and merge operations can overwrite remote history, close PRs, and change repository state in ways that affect collaborators. Documenting these commands without warnings or safeguards makes misuse more likely, especially in an automation skill where users may assume safe defaults.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The documentation instructs users on branch-cleanup operations that can delete branches and alter repository state, but it does not prominently warn about data loss or recommend dry-run/confirmation-first usage. In a GitHub automation context, this increases the likelihood of accidental destructive actions, especially when users rely on one-click cleanup behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The notification feature is documented as sending GitHub event data to Discord, DingTalk, Telegram, and Slack, but there is no privacy or data-handling warning. Repository names, PR titles, authors, issue numbers, and URLs can reveal sensitive internal development information when transmitted to third-party services.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The script calls gh auth logout -y during account switching when a config is missing, which forcibly terminates the user's current GitHub CLI session without an explicit warning or confirmation at that moment. In a multi-account helper, this can unexpectedly disrupt authenticated workflows, invalidate the active session for unrelated repositories, and cause accidental operations under a different account after re-login.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
98% confidence
Finding

The add-account flow also executes gh auth logout -y unconditionally before starting a new login, without a dedicated user warning that their existing GitHub CLI authentication will be removed. This is dangerous because the tool manages a global auth state, so adding one account can silently break current automation, repository access, or push/review operations tied to the previous login.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

This shell script embeds user-facing help text, usage instructions, and status messaging in Chinese only. Under the policy rule, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is clearly documented and justified, which is not present here.

Content

No source excerpt is available for this finding.

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · github-notify.sh (reported line 135)May include surrounding context.

sh
EOF
)
    
    curl -s -X POST \
        -H "Content-Type: application/json" \
        -d "$payload" \
        "$webhook_url" > /dev/null 2>&1

External Transmission

Medium
Category
Data Exfiltration
Confidence
70% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · github-notify.sh (reported line 190)May include surrounding context.

sh
local text=$(printf "%s\n%s" "$title" "$description")
    
    curl -s -X POST \
        "https://api.telegram.org/bot${bot_token}/sendMessage" \
        -d "chat_id=${chat_id}" \
        -d "text=${text}" > /dev/null 2>&1

External Transmission

Medium
Category
Data Exfiltration
Confidence
60% confidence
Finding

Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Content

Scanner excerpt · github-notify.sh (reported line 191)May include surrounding context.

sh
local text=$(printf "%s\n%s" "$title" "$description")
    
    curl -s -X POST \
        "https://api.telegram.org/bot${bot_token}/sendMessage" \
        -d "chat_id=${chat_id}" \
        -d "text=${text}" > /dev/null 2>&1

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The top-level documentation and help text describe the 'conflicts' command as processing conflicting PRs, which implies some operative handling. In reality, the handle_conflicts function only lists PRs with merge conflicts and echoes suggested git commands for a human to run, without performing conflict resolution or updating the PR.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The script performs destructive remote branch deletion immediately via git push origin --delete without any interactive confirmation, while the help text advertises a --yes flag that implies confirmation should normally exist. In a repository-maintenance skill, this increases the risk of accidental deletion of important branches, especially when branch names come from GitHub PR metadata and the tool is positioned as an automation helper.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
83% confidence
Finding

The help text advertises a -f, --force option, which implies a potentially destructive git push mode that can overwrite remote history, but there is no corresponding warning about that risk anywhere in the visible user guidance. Even though the option is not implemented in this file, documenting destructive behavior without a caution can mislead users about a safety-critical operation.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The header documentation describes the tool as a line-level PR review utility and says it generates/submits line-level comments, but the implemented comment path uses gh pr comment to add a general PR comment only. No code maps comments to files/lines or submits inline review comments, so the documentation overstates the implemented behavior.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The function is documented and presented to the user as approving a PR, but it calls gh pr review with --comment --body "LGTM! 👍" instead of an approval action. That means it only leaves a comment rather than performing the claimed approval operation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

This command triggers a state-changing GitHub action immediately, without confirmation, dry-run preview, or a clear warning that a review will be posted under the user's authenticated identity. In an agent-skill context, that increases the risk of accidental or socially engineered repository actions, especially if the tool is invoked on the wrong PR or repository.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The rejection/request-changes path posts directly to GitHub without confirmation or an explicit warning, creating a risk of unintended workflow disruption and reputational impact. In a multi-account GitHub helper, accidental execution is more dangerous because the authenticated account may have elevated permissions or act in the wrong organizational context.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

The manifest text for the skill and all listed sub-skills is written only in Chinese, with no indication that users can choose another language or that the skill is intentionally limited to a Chinese-speaking audience. Under the policy rule, a fixed language without opt-in or justification is a natural-language policy concern.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Low
Category
Not specified by scanner
Confidence
92% confidence
Finding

The script's help text, prompts, and status messages are entirely written in Chinese, which enforces a specific language for all users. The file provides no mechanism to select another language or explicitly document that the skill is intended only for a Chinese-speaking audience.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.