Back to skill

Security audit

git-batch-commit

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but its Git file handling can mis-handle specially named repository files and mutate the repo in unintended ways.

Use this only in repositories you trust, review the proposed groups before committing, and avoid the --yes mode until the Git path handling is fixed with '--' separators and NUL-delimited filename parsing. Be aware that optional sync/publish or subtree push workflows can upload skill contents or push to remotes if you explicitly confirm them.

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 (1)

T09 · Insecure Skill Coding Practices

Error
Location
scripts/interactive_commit.py:21
Finding
Git Option Injection Through Repository-Controlled Filenames<![CDATA[ ## Vulnerability Details **File Locations**: - `scripts/interactive_commit.py:21-50` - `scripts/categorize_changes.py:174-186` - `scripts/generate_commit_message.py:283-296` **Vulnerability Type**: Git command option injection **Risk Level**: High ### Vulnerable Code ```python def stage_files(files: List[str]) -> bool: """Stage files for commit.""" if not files: return True try: subprocess.run( ['git', 'add'] + files, capture_output=True, check=True ) return True except subprocess.CalledProcessError as e: print(f"暂存文件时出错: {e}", file=sys.stderr) return False def unstage_files(files: List[str]) -> bool: """Unstage files to reorganize commits.""" if not files: return True try: subprocess.run( ['git', 'reset', 'HEAD'] + files, capture_output=True, check=True ) return True except subprocess.CalledProcessError as e: print(f"取消暂存文件时出错: {e}", file=sys.stderr) return False ``` The same unsafe path handling occurs during diff analysis: ```python def detect_code_change_type(filepath: str) -> str: """ Detect if a source code change is feat, fix, refactor, or style. This analyzes the git diff content. """ try: result = subprocess.run( ['git', 'diff', '--cached', filepath], capture_output=True, text=True, check=True ) ``` ```python def get_file_diff(filepath: str) -> str: """Get git diff for a specific file (cached).""" if filepath in _diff_cache: return _diff_cache[filepath] try: result = subprocess.run( ['git', 'diff', '--cached', filepath], capture_output=True, text=True, ) _diff_cache[filepath] = result.stdout return result.stdout except Exception: return "" ``` ### Technical A ...[truncated 3106 chars]
Remediation
<![CDATA[ ## Remediation Suggestions Place Git's `--` option terminator before every repository-controlled path: ```python def stage_files(files: List[str]) -> bool: if not files: return True try: subprocess.run( ['git', 'add', '--', *files], capture_output=True, check=True ) return True except subprocess.CalledProcessError as e: print(f"Error staging files: {e}", file=sys.stderr) return False def unstage_files(files: List[str]) -> bool: if not files: return True try: subprocess.run( ['git', 'reset', 'HEAD', '--', *files], capture_output=True, check=True ) return True except subprocess.CalledProcessError as e: print(f"Error unstaging files: {e}", file=sys.stderr) return False ``` Apply the same protection to all per-file diff commands: ```python subprocess.run( ['git', 'diff', '--cached', '--', filepath], capture_output=True, text=True, check=True ) ``` Use NUL-delimited Git output to handle all valid filenames safely: ```python result = subprocess.run( ['git', 'diff', '--cached', '--name-only', '-z'], capture_output=True, check=True ) files = [ value.decode('utf-8', errors='surrogateescape') for value in result.stdout.split(b'\0') if value ] ``` Additional hardening should include: 1. Add tests covering filenames such as `--hard`, `--all`, names containing spaces, and names containing newline characters. 2. Preserve the original index state before unstaging all files. 3. If any group fails, restore or restage the remaining original entries rather than leaving the index partially modified. 4. Validate that every grouped path is present in the original staged-file set before invoking Git. 5. Continue using subprocess argument arrays and do not replace them with shell command strings. ]]>
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • 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
Findings (30)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
主要功能与声明的大方向基本一致:代码确实只围绕已暂存变更的分组拆分提交和提交信息生成展开,没有实现 push、merge、PR 等越权行为,符合“只负责 commit 拆分和提交信息生成”的主旨。但声明中一个明确的后置行为——提交完成后若存在 clawhub-sync 或 subtree-publish 配置则提示是否同步发布——在该代码片段中完全不存在,因此描述包含了代码未体现的重要行为。另有一个较小差异:代码支持给提交消息追加 Issue/本地任务引用,其中 GitHub Issue 引用是声明未明确写出的能力,不过它仍属于提交信息生成范畴,严重性较低。综合判断,存在描述与实际行为不完全一致的情况,应标记为 mismatch。

Ae1

High
Category
analysis-evasion
Content
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill explicitly describes executing local commands via subprocess, including git and potentially publishing tools, but it does not declare any tool scope such as permissions or allowed-tools. This weakens enforcement and auditability: a caller or platform cannot reliably constrain what the skill is allowed to execute, increasing the chance of overbroad shell access or accidental command execution beyond the stated purpose.

Natural-Language Policy Violations

Medium
Confidence
89% confidence
Finding
This markdown file contains all operational instructions, prompts, and user-facing disclosures in Chinese only. Under the policy, forcing a specific language without user opt-in is a natural-language policy violation unless the locale constraint is explicitly justified, which is not stated here.

Vague Triggers

Medium
Confidence
89% confidence
Finding
L50 使用“包含大量添加内容的源代码文件”作为触发条件,但“大量”没有量化标准,也未说明与其他类别的优先级关系。这样的激活条件不够具体,可能导致不同修改被不一致地归类为新功能。

Vague Triggers

Medium
Confidence
87% confidence
Finding
L57 与 L61 说明通过 diff 中的 "fix"、"bug"、"issue"、"error" 等关键字检测 `fix`,这些词在注释、日志、文档或上下文字符串中都很常见。文档未提供负例、上下文约束或优先级规则,容易造成误判触发。

Vague Triggers

Medium
Confidence
94% confidence
Finding
L71 将 `style` 定义为“源代码文件(默认类别)”,但没有说明何时不应归入该类别,也没有给出排除条件。作为默认触发,这种描述过于宽泛,容易在本应判定为 feat、fix 或 refactor 的普通代码修改中误触发该类别。

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
L83 明确规定“描述使用中文”,属于对输出语言的强制性限制。文件中没有提供用户可选择其他语言的选项,也没有说明这是特定地区或合规场景下的必要约束。

Natural-Language Policy Violations

Medium
Confidence
92% confidence
Finding
The entire skill is written as a prescriptive specification in Chinese, with no indication that users may choose another language or locale. Under the policy rule, forcing a specific language without opt-in is a natural-language policy violation unless the locale restriction is documented and justified.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The skill file is written entirely in Chinese and the user-facing prompt example is also fixed in Chinese, with no indication that the user may choose another language. This creates a language-policy issue because it implicitly requires a specific language for interaction without opt-in or documented justification.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_staged_files() -> List[str]:
    """Get list of staged files using git diff --cached --name-only."""
    result = subprocess.run(
        ['git', 'diff', '--cached', '--name-only'],
        capture_output=True,
        text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def get_unstaged_files() -> List[str]:
    """Get list of unstaged modified files using git diff --name-only."""
    result = subprocess.run(
        ['git', 'diff', '--name-only'],
        capture_output=True,
        text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
This analyzes the git diff content.
    """
    try:
        result = subprocess.run(
            ['git', 'diff', '--cached', filepath],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The change-type detection logic explicitly includes Chinese keyword lists alongside English ones in comments and code, which embeds a specific language policy into behavior. Because the script does not offer user-configurable language selection or document a region-specific requirement, this is a natural-language locale policy issue under the stated rule.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The module documentation explicitly requires commit messages to use Chinese punctuation/description conventions and later user-facing CLI text is also presented in Chinese. This enforces a specific language/locale choice rather than offering the user a language option or documenting a justified region-specific constraint.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if filepath.endswith('SKILL.md'):
            try:
                # 使用 git cat-file 检查文件是否在 HEAD 中存在
                result = subprocess.run(
                    ['git', 'cat-file', '-e', f'HEAD:{filepath}'],
                    capture_output=True,
                    text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if filepath in _diff_cache:
        return _diff_cache[filepath]
    try:
        result = subprocess.run(
            ['git', 'diff', '--cached', filepath],
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Context-Inappropriate Capability

Medium
Confidence
88% confidence
Finding
The manifest says this skill only handles commit splitting and commit message generation, and explicitly defers Issue-related semantics to git-workflow. This file implements issue/task reference injection into commit subjects and bodies, which is an additional Issue-traceability capability not necessary for generating commit messages from staged changes.

Description-Behavior Mismatch

Medium
Confidence
91% confidence
Finding
The manifest limits this skill to commit splitting and commit message generation, and states that Issue closing semantics should follow git-workflow. Even though the code avoids closing issues, the public CLI still accepts --issue and --local-ref options and modifies commit messages accordingly, expanding behavior beyond the described scope.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not files:
        return True
    try:
        subprocess.run(
            ['git', 'add'] + files,
            capture_output=True,
            check=True
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Natural-Language Policy Violations

Medium
Confidence
96% confidence
Finding
This code file contains multiple user-facing strings in Chinese, beginning at L033 and continuing throughout the interactive flow, but it does not provide any opt-in language selection or indicate that the tool is intended only for Chinese-speaking users. That creates a natural-language locale policy issue because the skill effectively forces a specific language on all users.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
if not files:
        return True
    try:
        subprocess.run(
            ['git', 'reset', 'HEAD'] + files,
            capture_output=True,
            check=True
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.