Back to skill

Security audit

github-desktop-zh

Security checks for vulnerabilities and agentic risk

Overview

This GitHub Desktop Chinese localization skill is not deceptive, but it needs Review because it rewrites installed application code and has confirmed flaws that can corrupt installs or let custom dictionaries write or inject outside the intended scope.

Install only if you are comfortable with a skill that patches GitHub Desktop's installed code. Use dry-run first, close GitHub Desktop, keep backups enabled, avoid --force and --no-backup, and do not use custom dictionaries unless you fully trust and inspect them. ASAR-mode users should be prepared to reinstall GitHub Desktop if deployment corrupts the archive.

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/apply_zh.py:281
Finding

Custom Dictionary Filenames Permit Arbitrary File Read and Overwrite

Content
View full analysis
3 else "renderer.js" ``` ```python written = [] for fname, content in working.items(): has_bom = files[fname][1] out_path = os.path.join(output_dir, fname) write_js_file(out_path, content, has_bom) written.append(out_path) ``` ```python files = {} for fname in file_names: path = os.path.join(src_base, fname) if os.path.exists(path): content, has_bom = read_js_file(path) files[fname] = (content, has_bom) else: print(f"[WARN] Source file does not exist: {fname}") ``` ### Technical Analysis The fourth field of each dictionary entry controls `src_file`. This value is accepted without validating that it is a simple filename or that its resolved path remains inside the GitHub Desktop source and output directories. For an absolute `src_file`, `os.path.join(src_base, fname)` and `os.path.join(output_dir, fname)` discard the trusted base directory and resolve to the attacker-supplied path. Relative values containing parent-directory components can similarly escape the intended directory. If the resulting path exists and contains UTF-8 data, `_load_source_files` reads it and adds it to the working file map. `apply_translations` can subsequently write translated content back to the same external path. This write occurs even when `--deploy` is not supplied; deployment controls copying into GitHub Desktop, not creation of translation output. ### Attack Path 1. An attacker creates a custom dictionary whose fourth field contains an absolute path or a traversal path such as `../../target.js`. 2. The attacker persuades the user or agent to invoke the documented `--dict` option with that dictionary. 3. `load_dict` accepts the untru ...[truncated 977 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/apply_zh.py:479
Finding

Unescaped Translation Targets Can Inject JavaScript into GitHub Desktop

Content
View full analysis
0: return new_content, count # Long source fallback if len(source) >= SUBSTR_FALLBACK_MIN_LEN and " " in source: c = content.count(source) if c > 0: return content.replace(source, target), c return content, 0 ``` ### Technical Analysis The `source` value is escaped for regular-expression matching, but the attacker-controlled `target` is inserted into JavaScript without JavaScript string serialization. A target containing the active quote character, backslashes, line terminators, or other JavaScript syntax can terminate the original string literal and introduce new executable statements. The fallback is more dangerous because it performs an unrestricted textual replacement and is not confined to a parsed string-literal node. It can alter comments, template expressions, object syntax, or executable code. The optional `node --check` validation does not mitigate this issue. It only detects syntax errors; a malicious payload can be valid JavaScript and pass the check. Validation is also skipped when Node.js is unavailable and is not applied directly to ASAR contents. ### Attack Path 1. An attacker creates a custom dictionary with a source that is known to occur in GitHub Desktop. 2. The corresponding target contains a quote-breaking, syntactically valid JavaScript payload. 3. The user or agent inv ...[truncated 967 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/apply_zh.py:811
Finding

ASAR Deployment Repackages an Incomplete Staging Directory

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Warning
Location
SKILL.md:57
Finding

Documentation Recommends an Unpinned Global npm Dependency

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • 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
Findings (18)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding

Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Content

No source excerpt is available for this finding.

Lp1

High
Category
MCP Least Privilege
Confidence
90% confidence
Finding

The script has shell/process-execution capability via multiple subprocess calls, but the skill metadata does not declare that capability. In an agent or plugin ecosystem, undeclared execution primitives materially increase risk because users and policy layers may not realize the skill can invoke external programs and modify installed application files.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The README explicitly instructs users to deploy changes that overwrite GitHub Desktop application files, but it does not clearly warn that modifying installed binaries/resources can break the application, invalidate updates, or leave it in an unsupported state. In this skill's context, the core function is patching app files in place, so missing safety warnings materially increase the chance of accidental integrity damage even if the intent is customization rather than compromise.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

Documenting a --force mode that allows modification while GitHub Desktop is running is risky because active processes may hold files open, partially apply changes, or load inconsistent code, leading to corruption or unstable behavior. This skill is more dangerous than a generic file-editing tool because it targets live application code (main.js / renderer.js) inside an installed Electron app.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The trigger set includes broad phrases for app localization workflows, and the analyzer indicates at least one trigger may collide with common user requests. In this skill, activation leads to use of Shell/Edit/Write capabilities and can modify installed application files, so accidental invocation could cause unintended code/resource patching or rollback actions on the local system.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

Several triggers such as '应用汉化', '恢复原版', '回滚', and '撤销汉化' are ambiguous outside the specific GitHub Desktop context. Because this skill can run shell commands and write to application resources, ambiguous activation increases the chance that unrelated user requests are interpreted as permission to alter installed software or revert files.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

This .txt file is a translation dictionary whose entries consistently map English UI strings into Chinese, indicating the skill content is fixed to a specific locale. Under the policy, forcing a language or locale without offering a user choice or documenting an opt-in is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

This code file contains user-facing natural-language descriptions and messages that present the tool exclusively as a Chinese localization utility for GitHub Desktop, with no indication of optional language selection or user opt-in for locale behavior. The policy requires flagging language or locale constraints when a skill forces a specific language without offering choice or documenting a justified regional/compliance reason.

Content

No source excerpt is available for this finding.

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 64)May include surrounding context.

python
def _command_available(cmd_args):
    try:
        subprocess.run(cmd_args, capture_output=True, timeout=3)
        return True
    except FileNotFoundError:
        return False

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 135)May include surrounding context.

python
def _query_reg(hive, value_name):
    try:
        result = subprocess.run(
            ["reg", "query", hive, "/v", value_name],
            capture_output=True, text=True, timeout=5,
        )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 198)May include surrounding context.

python
def check_asar_available():
    """检测 asar 命令是否可用。"""
    try:
        result = subprocess.run(
            ["asar", "--version"], capture_output=True, timeout=5,
        )
        return result.returncode == 0

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
78% confidence
Finding

The script executes the external 'asar' binary from PATH on a user-supplied or auto-detected archive path, which creates a tool trust boundary. If PATH is hijacked or a malicious 'asar' binary is installed earlier in PATH, running this script can trigger unintended code execution under the user's privileges.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 212)May include surrounding context.

python
"""解包 asar 到 dest_dir,失败 sys.exit。"""
    try:
        os.makedirs(dest_dir, exist_ok=True)
        result = subprocess.run(
            ["asar", "extract", asar_path, dest_dir],
            capture_output=True, text=True, timeout=120,
        )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
78% confidence
Finding

This packs content by invoking an external 'asar' executable found via PATH, again trusting ambient system state rather than a pinned binary. In a compromised developer workstation or hostile PATH environment, this can execute an attacker-controlled program.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 230)May include surrounding context.

python
def pack_asar(src_dir, asar_path):
    """打包 src_dir 为 asar 文件,失败 sys.exit。"""
    try:
        result = subprocess.run(
            ["asar", "pack", src_dir, asar_path],
            capture_output=True, text=True, timeout=300,
        )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
74% confidence
Finding

The script invokes 'node' from PATH to syntax-check modified JavaScript files. While the file argument is not executed as shell input, trusting an unqualified 'node' executable means a malicious binary earlier in PATH could be executed.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 556)May include surrounding context.

python
# asar 文件不做 node --check;loose js 文件做语法校验
        if f.endswith(".js") and node_available:
            try:
                result = subprocess.run(
                    ["node", "--check", f], capture_output=True, timeout=30,
                )
                if result.returncode == 0:

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 652)May include surrounding context.

python
if sys.platform == "win32":
        for proc in ("GitHubDesktop.exe", "Update.exe"):
            try:
                result = subprocess.run(
                    ["tasklist", "/FI", f"IMAGENAME eq {proc}"],
                    capture_output=True, text=True, timeout=5,
                )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 665)May include surrounding context.

python
# macOS / Linux: pgrep
    for pattern in ("GitHub Desktop", "github-desktop", "GitHubDesktop"):
        try:
            result = subprocess.run(
                ["pgrep", "-f", pattern],
                capture_output=True, text=True, timeout=5,
            )

subprocess module call

Medium
Category
Dangerous Code Execution
Confidence
70% confidence
Finding

subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Content

Scanner excerpt · scripts/apply_zh.py (reported line 674)May include surrounding context.

python
except FileNotFoundError:
            # 回退到 ps
            try:
                result = subprocess.run(
                    ["ps", "-A"], capture_output=True, text=True, timeout=5,
                )
                for line in result.stdout.splitlines():

Overly Broad Trigger

Low
Category
Trigger Abuse
Confidence
96% confidence
Finding

The standalone trigger '回滚' is extremely short and generic, making unintended activation likely in many unrelated conversations about reverting changes. In this skill context, activation could initiate rollback logic affecting application files, backups, or deployments, which raises the risk from a simple routing issue to unintended local file modification.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.