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

Content
View full analysis
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
View remediation
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。

Content

No source excerpt is available for this finding.

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 82)May include surrounding context.

md
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 86)May include surrounding context.

md
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 93)May include surrounding context.

md
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 101)May include surrounding context.

md
**重要规则**:`SKILL.md` 虽然是 Markdown 格式,但它是**技能的核心功能文件**,不应归类为 `docs` 类型。

Undeclared Tool Scope

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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

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

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
87% confidence
Finding

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

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

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

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

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

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

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/categorize_changes.py (reported line 129)May include surrounding context.

python
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,

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/categorize_changes.py (reported line 141)May include surrounding context.

python
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,

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/categorize_changes.py (reported line 180)May include surrounding context.

python
This analyzes the git diff content.
    """
    try:
        result = subprocess.run(
            ['git', 'diff', '--cached', filepath],
            capture_output=True,
            text=True,

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

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/generate_commit_message.py (reported line 126)May include surrounding context.

python
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,

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/generate_commit_message.py (reported line 288)May include surrounding context.

python
if filepath in _diff_cache:
        return _diff_cache[filepath]
    try:
        result = subprocess.run(
            ['git', 'diff', '--cached', filepath],
            capture_output=True,
            text=True,

Context-Inappropriate Capability

Medium
Category
Not specified by scanner
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.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
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.

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/interactive_commit.py (reported line 26)May include surrounding context.

python
if not files:
        return True
    try:
        subprocess.run(
            ['git', 'add'] + files,
            capture_output=True,
            check=True

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
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.

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/interactive_commit.py (reported line 42)May include surrounding context.

python
if not files:
        return True
    try:
        subprocess.run(
            ['git', 'reset', 'HEAD'] + files,
            capture_output=True,
            check=True