Back to skill

Security audit

GitHub Issue Auto Triage

Security checks for vulnerabilities and agentic risk

Overview

The skill is mostly coherent, but it should be reviewed because it can change GitHub issues, send issue content to DashScope, and asks for broader GitHub token access than issue triage needs.

Install only after limiting the GitHub credential to the target repository and issue permissions, confirming that sending issue content to DashScope is acceptable for your project, and starting with dry-run while understanding that dry-run still contacts the LLM provider. Avoid cron or systemd deployment until labels, comments, and token scopes have been reviewed by the repository owner.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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 (3)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/triage.py:125
Finding
Issue Content Is Sent to a Third-Party LLM Without an Explicit Enablement or Privacy Control## Vulnerability Details **File Location**: `scripts/triage.py`, lines 125-168 **Vulnerability Type**: Uncontrolled disclosure of repository issue content to a third-party service **Risk Level**: Medium **Vulnerable Code**: ```python def _llm_classify(self, title: str, body: str) -> Optional[str]: """使用 LLM 分类 Issue""" prompt = f""" 请分析这个 GitHub Issue 并分类为以下类型之一:bug, enhancement, question, documentation 标题:{title} 描述:{body[:500]} 只返回类型名称(bug/enhancement/question/documentation),不要其他内容。 """ try: # 调用 DashScope API url = 'https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation' headers = { 'Authorization': f'Bearer {DASHSCOPE_API_KEY}', 'Content-Type': 'application/json' } data = { 'model': 'qwen-plus', 'input': { 'messages': [ {'role': 'user', 'content': prompt} ] } } response = requests.post(url, headers=headers, json=data) response.raise_for_status() ``` The API key is described as optional, but the fallback value does not disable the integration: ```python DASHSCOPE_API_KEY = os.getenv('DASHSCOPE_API_KEY', 'sk-xxx') ``` ### Technical Analysis Every classification invokes `_llm_classify`, which embeds the complete issue title and the first 500 characters of the issue body in a request to DashScope. There is no dedicated configuration switch, consent gate, content-redaction stage, or check that a real DashScope key has been configured. Consequently, the program attempts to disclose issue content even when the user has not configured the supposedly optional AI integration. An invalid key may cause the service to reject processing, but the HTTP request body still reaches the third-party endpoint. This behavior also occurs in `--dry-run` mode: dry-run prevents GitHub modifi ...[truncated 1552 chars]
Remediation
## Remediation Suggestions 1. Make LLM processing explicitly opt-in, for example with `triage.use_llm: false` as the secure default. 2. Do not assign a placeholder API key as a functional default. Use an empty value and skip `_llm_classify` unless a nonempty key is present. 3. Clearly disclose that issue content is sent to DashScope before enabling the integration. 4. Add a local-only mode and ensure `--dry-run` does not contact third-party AI services unless the user separately requests it. 5. Redact likely secrets, credentials, email addresses, internal URLs, and other configured patterns before constructing the prompt. 6. Allow administrators to restrict which repositories and issue fields may be processed externally. 7. Add explicit request timeouts, such as `timeout=(5, 30)`, and bounded retry behavior. 8. Add tests verifying that no DashScope request occurs when the API key or opt-in setting is absent. 9. Document the provider's retention, regional processing, and privacy implications.

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
README.md:153
Finding
Documentation Requests GitHub Permissions Beyond Those Required for Issue Triage## Vulnerability Details **File Location**: `README.md`, lines 153-161 **Vulnerability Type**: Excessive GitHub token permissions **Risk Level**: Medium **Vulnerable Documentation**: ```markdown ## 🔧 GitHub Token 获取 1. 访问 https://github.com/settings/tokens 2. 点击 "Generate new token" 3. 选择权限: - ✅ `repo` (完整仓库权限) - ✅ `read:user` (读取用户信息) 4. 生成并复制 Token 5. 设置环境变量:`export GITHUB_TOKEN="your_token"` ``` ### Technical Analysis The documented classic-token `repo` scope grants broad control over repository content and settings, while `read:user` permits access to user profile data. The audited implementation only reads issues and writes issue labels, assignees, and comments. It does not use the authenticated-user API, so `read:user` is unnecessary. Recommending broad classic-token scopes contradicts the project's claim that it follows least privilege. The script places the token in every request to the repository API, so compromise of the process environment, scheduled-task context, log-adjacent debugging environment, or host account exposes a credential with substantially greater authority than the task requires. ### Attack Path 1. An administrator follows the README and creates a classic personal access token with full `repo` and `read:user` scopes. 2. The token is made available to the triage process through its environment or scheduled-service configuration. 3. An attacker obtains the token through a compromised host account, process environment disclosure, insecure service configuration, shell history, or another local credential leak. 4. The attacker uses the token directly against GitHub APIs. 5. Because the token has broad repository scope, the attacker can perform operations beyond issue triage, subject to the issuing user's repository access. ### Impact Assessment The code itself does not exploit the excessive permissions. However, following the documented setup can produce a credential capable ...[truncated 340 chars]
Remediation
## Remediation Suggestions 1. Recommend a fine-grained GitHub personal access token or GitHub App installation token instead of a classic token. 2. Restrict repository access to only the repositories being triaged. 3. Request only the minimum repository permissions needed: - Issues: read and write. - Metadata: read, where required by GitHub. - No user-profile permission unless a future feature demonstrably needs it. 4. Remove the `read:user` recommendation because the current implementation does not call user APIs. 5. Document separate read-only permissions for local preview workflows where possible. 6. Encourage short token expiration, regular rotation, and organization approval controls. 7. Prefer a GitHub App with narrowly scoped installation access for unattended cron or systemd deployment. 8. Add startup documentation that explains why each requested permission is required.

T09 · Insecure Skill Coding Practices

Note
Location
config.example.json:1
Finding
Credential Setup Guidance Encourages Plaintext Token Storage and Terminal Disclosure## Vulnerability Details **File Location**: `config.example.json`, lines 1-14; `README.md`, lines 227-230 **Vulnerability Type**: Unsafe credential handling guidance **Risk Level**: Low **Vulnerable Configuration Guidance**: ```text # GitHub Issue Auto Triage - 测试配置 # GitHub 配置(示例) GITHUB_TOKEN="your_github_token_here" GITHUB_OWNER="openclaw" GITHUB_REPO="openclaw" # AI 配置(可选) DASHSCOPE_API_KEY="sk-your-key-here" # 使用说明: # 1. 复制此文件为 .env # 2. 填入真实的 Token # 3. 运行:source .env && python3 scripts/triage.py --dry-run ``` The troubleshooting section additionally recommends printing the secret: ```bash echo $GITHUB_TOKEN # 应该显示你的 Token ``` ### Technical Analysis The example file is named `config.example.json`, but its contents use shell assignment syntax and are intended to be copied into a plaintext `.env` file. The project does not include a visible `.gitignore` rule protecting `.env`, and the instructions do not require restrictive file permissions. This creates a credible risk that users will commit the file, leave it readable by other local users, include it in backups, or otherwise expose it. Recommending `echo $GITHUB_TOKEN` displays the complete credential in terminal output. The token may then be exposed through screen sharing, terminal recording, CI logs, support transcripts, or copied command output. The same concerns apply to the DashScope API key. ### Attack Path 1. A user copies `config.example.json` to `.env` and inserts live GitHub and DashScope credentials. 2. The user does not restrict the file mode or exclude the file from version control because those controls are not documented or supplied. 3. The file is committed, archived, copied, or read by another local account. 4. Alternatively, the user follows troubleshooting guidance and prints the complete GitHub token into a captured terminal. 5. An attacker who obtains the exposed value authenticates to GitHub or DashScope with the ...[truncated 434 chars]
Remediation
## Remediation Suggestions 1. Rename the example to `.env.example` so its format and purpose are unambiguous. 2. Add `.env`, generated result files, logs, and local secret files to a committed `.gitignore`. 3. Instruct users to apply restrictive permissions, such as `chmod 600 .env`. 4. Prefer an operating-system secret store, GitHub App credential mechanism, container secret, or systemd credential facility for unattended deployment. 5. Remove the `echo $GITHUB_TOKEN` instruction. Recommend checking only whether the variable is set, for example: ```bash test -n "$GITHUB_TOKEN" && echo "GITHUB_TOKEN is set" ``` 6. Warn users not to paste credentials into issue reports, chat sessions, logs, screenshots, or shell command history. 7. Document immediate revocation and rotation procedures for accidentally exposed credentials.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
Findings (34)

Tainted flow: 'headers' from os.getenv (line 154, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Content
}
            }
            
            response = requests.post(url, headers=headers, json=data)
            response.raise_for_status()
            result = response.json()
Confidence
90% confidence
Finding
Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding
The documented purpose understates important side effects and data flows: issue content may be sent to an external LLM provider, local write side effects are implied by logging/records, and the behavior description is inconsistent with the implementation claims. This mismatch is dangerous because operators may authorize the skill without understanding that third parties receive issue data or that local state may be written, leading to privacy, compliance, and change-management failures.

Credential Access

High
Category
Privilege Escalation
Content
DASHSCOPE_API_KEY="sk-your-key-here"

# 使用说明:
# 1. 复制此文件为 .env
# 2. 填入真实的 Token
# 3. 运行:source .env && python3 scripts/triage.py --dry-run
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
DASHSCOPE_API_KEY="sk-your-key-here"

# 使用说明:
# 1. 复制此文件为 .env
# 2. 填入真实的 Token
# 3. 运行:source .env && python3 scripts/triage.py --dry-run
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The configuration section tells users to export GITHUB_TOKEN and DASHSCOPE_API_KEY but provides no guidance on minimum token scope, secure storage, rotation, or avoiding shell-history/log exposure. Because this skill operates against GitHub repositories, overprivileged or poorly handled tokens could allow unintended repository changes or credential leakage if copied into shared environments.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The guide instructs users to run an automated triage script on live GitHub issues, but it does not clearly warn that execution may change repository state by adding labels, assigning owners, or posting replies. In a repository-automation skill, omission of this warning increases the chance of unintended modifications, especially if users skip dry-run mode or grant broad repository permissions.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The skill documentation is written almost entirely in Chinese, including usage, warnings, and operational instructions, without indicating that other languages are supported or that Chinese is required for a justified region-specific reason. This can violate a language/locale policy when users are not given an explicit language choice or opt-in.

Intent-Code Divergence

Medium
Confidence
95% confidence
Finding
The README states adherence to least privilege, but the setup instructions tell users to grant a full `repo` token, which is broader than necessary for issue triage. If that token is exposed through logs, shell history, cron/systemd environment leakage, or host compromise, an attacker could gain extensive repository access beyond issue management, including code, secrets, and administrative actions permitted by the token scope.

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill declares automation that reads issue content, uses environment-backed credentials, calls external services, and can modify GitHub issues, but it does not declare any explicit tool scope such as permissions or allowed-tools. This creates a confused-deputy risk where the runtime may grant broader capabilities than users expect, reducing transparency and making unintended data access or write actions more likely.

Missing User Warnings

Medium
Confidence
87% confidence
Finding
The skill description advertises automatic triage behavior but does not clearly warn that it can perform write operations on GitHub issues, such as adding labels, assigning owners, replying, or marking items resolved. Users may invoke it expecting analysis-only behavior and unintentionally cause repository changes, which is particularly risky in shared or production repos.

Vague Triggers

Medium
Confidence
88% confidence
Finding
The manual trigger phrase includes a broad natural-language form ('处理 GitHub Issue') that can overlap with ordinary conversation. In agent environments, ambiguous triggers can cause accidental activation of an automation that performs labeling, assignment, replies, and notifications, resulting in unintended writes to production repositories.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The skill states it uses an LLM but does not clearly disclose that issue titles and descriptions may be transmitted to an external AI provider for analysis. This is a privacy and data-governance risk because issue content often contains internal details, stack traces, credentials by mistake, or sensitive business context.

External Transmission

Medium
Category
Data Exfiltration
Content
### API 调用
```bash
curl -X POST http://localhost:8080/api/triage \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -d '{"repo": "owner/repo", "issue_number": 123}'
```
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The report describes live GitHub issue triage actions such as adding labels, assigning owners, and posting replies, but does not clearly warn that these operations will modify repository state and workflow when not run in dry-run mode. In an automation skill context, this can lead users to execute repository-changing actions without fully understanding the operational impact, causing unintended workflow disruption or noisy/incorrect issue mutations.

Missing User Warnings

Medium
Confidence
97% confidence
Finding
The production deployment section instructs users to schedule the script via cron every 30 minutes but does not clearly warn that this will repeatedly perform live triage actions against the repository. Recurring unattended execution increases the blast radius of misclassification, bad auto-replies, incorrect assignments, or API misuse because mistakes will be repeated automatically over time.

Session Persistence

Medium
Category
Rogue Agent
Content
pip install requests

# 2. 配置定时任务
crontab -e
# 添加:*/30 * * * * cd /path/to/skill && python3 scripts/triage.py

# 3. 监控日志
Confidence
85% confidence
Finding
Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
The manifest description is written only in Chinese ("自动分类 GitHub Issue,AI 智能打标签、分配负责人、检测重复、回复 FAQ") with no indication that users can choose another language. This can violate language/locale policy when a skill implicitly constrains interaction or documentation to a single language without opt-in or justification.

Natural-Language Policy Violations

Medium
Confidence
85% confidence
Finding
The description is written entirely in Chinese and presents the skill's user-facing behavior in that language, with no indication that users can opt into another language or locale. Under the policy rules, a skill that appears to enforce a specific language without opt-in can be a natural-language policy violation unless the locale restriction is explicitly justified.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The comments and usage instructions are written entirely in Chinese, which imposes a language choice on users without any opt-in or alternative locale. This matches the policy category for language or locale constraints expressed in natural language.

Natural-Language Policy Violations

Medium
Confidence
88% confidence
Finding
The file-level description and many user-facing messages are written only in Chinese, indicating a fixed language choice rather than offering a user-selectable locale. This can violate language/locale policy when the skill does not document that it is region-specific or provide an opt-in choice.

External Transmission

Medium
Category
Data Exfiltration
Content
'Authorization': f'token {GITHUB_TOKEN}',
            'Accept': 'application/vnd.github.v3+json'
        }
        self.base_url = f'https://api.github.com/repos/{GITHUB_OWNER}/{GITHUB_REPO}'
    
    def get_uncategorized_issues(self, limit: int = 10) -> List[Dict]:
        """获取未分类的 Issue"""
Confidence
60% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
Issue title/body content is sent to an external LLM provider for classification, but the workflow gives no consent notice, redaction step, or repository-level control for sensitive projects. Users may unknowingly disclose private bug details, internal URLs, credentials pasted into issues, or embargoed security information to a third party.

Ssd 1

Medium
Confidence
92% confidence
Finding
The code embeds untrusted issue title/body text directly into the LLM prompt, so a malicious reporter can include prompt-injection content to influence classification. In this skill the effect is bounded because the model output is constrained to a small label set, but it can still cause mislabeling, workflow manipulation, or suppression of correct triage outcomes.

External Transmission

Medium
Category
Data Exfiltration
Content
}
            }
            
            response = requests.post(url, headers=headers, json=data)
            response.raise_for_status()
            result = response.json()
Confidence
94% confidence
Finding
This outbound request transmits issue-derived content to DashScope, a third-party external service. In the context of issue triage, repository issues may contain sensitive operational details or accidentally pasted secrets, so external transmission meaningfully increases confidentiality risk.

External Transmission

Medium
Category
Data Exfiltration
Content
url = f'{self.base_url}/issues/{issue_number}/labels'
        data = {'labels': labels}
        
        response = requests.post(url, headers=self.github_headers, json=data)
        return response.status_code == 200
    
    def assign_issue(self, issue_number: int, assignee: str) -> bool:
Confidence
80% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Static analysis

No suspicious patterns detected.