Back to skill

Security audit

Git Repo Cleaner

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate Git repository audit tool, but its generated cleanup script can run unintended shell commands or modify the wrong repository if executed.

Install only if you are comfortable treating this as a review-needed tool. Running normal audits is consistent with its purpose, but do not execute cleanup output from --fix as-is, especially on untrusted repositories. Check every generated command, bind it to the intended repository, avoid --force-delete unless you have backups or remote copies, and avoid immediate pruning unless you understand the recovery impact.

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
scripts/audit_repo.py:384
Finding

Shell Command Injection Through Attacker-Controlled Git Branch Names

Content
View full analysis

Vulnerability Details

File Location: scripts/audit_repo.py, lines 384–395
Vulnerability Type: Shell command injection in generated cleanup script
Risk Level: High

Vulnerable Code

python
if branch_findings.get("merged"):
    lines.append("# === Delete merged branches ===")
    for b in branch_findings["merged"]:
        lines.append(f'echo "Deleting merged branch: {b["name"]}"')
        lines.append(f'git branch {delete_flag} "{b["name"]}"')
    lines.append("")

if branch_findings.get("stale"):
    lines.append("# === Delete stale branches (review carefully!) ===")
    for b in branch_findings["stale"]:
        lines.append(f'# Stale {b["days_old"]} days, last: {b["last_subject"][:50]}')
        if force_delete:
            lines.append(f'git branch -D "{b["name"]}"')
        else:
            lines.append(f'# git branch -D "{b["name"]}"  # Uncomment after review')

Technical Analysis

Branch names are read from the repository and interpolated directly into shell commands. The generated commands enclose branch names in double quotes, but double quotes do not disable shell command substitution through constructs such as $() or backticks.

Consequently, a branch name containing shell metacharacters accepted by Git can introduce executable shell expressions into the generated cleanup script. The expressions are evaluated when the user executes that script. The vulnerable values are used both in an echo command and in branch-deletion commands.

Although --fix prints rather than automatically executes the cleanup script, the documented workflow explicitly directs users to save, review, and execute it. This creates a direct path from untrusted repository metadata to local command execution.

Attack Path

  1. An attacker creates or supplies a Git repository containing a maliciously named stale or merged branch.
  2. The victim runs the audit tool against that repository with ...[truncated 902 chars]
Remediation
View remediation

Remediation Suggestions

  • Apply robust shell escaping to every repository-derived value using shlex.quote().
  • Insert the Git end-of-options marker before branch names, for example: git branch -d -- "$branch".
  • Validate branch names and reject values containing unsafe or unexpected shell syntax.
  • Prefer generating a structured data file and using a trusted Python cleanup program that invokes Git through subprocess.run() with an argument list and shell=False.
  • If shell output must be generated, assign safely quoted values to variables and never interpolate raw repository metadata into executable shell source.
  • Add automated tests using branch names containing $(), backticks, dollar signs, parentheses, and other shell-significant characters.
  • Clearly warn users that cleanup output generated from an untrusted repository must not be executed without validation.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/audit_repo.py:373
Finding

Generated Cleanup Script Can Modify the Wrong Git Repository

Content
View full analysis

Vulnerability Details

File Location: scripts/audit_repo.py, lines 373–402
Vulnerability Type: Missing repository binding in destructive cleanup commands
Risk Level: Medium

Vulnerable Code

python
def generate_cleanup_script(repo_path, branch_findings, force_delete=False):
    """Generate a cleanup shell script."""
    lines = ["#!/bin/bash", f'# Git Repo Cleanup Script for {repo_path}',
             f'# Generated: {datetime.now().isoformat()}', "",
             'set -e', ""]

    delete_flag = "-D" if force_delete else "-d"

    if branch_findings.get("merged"):
        lines.append("# === Delete merged branches ===")
        for b in branch_findings["merged"]:
            lines.append(f'echo "Deleting merged branch: {b["name"]}"')
            lines.append(f'git branch {delete_flag} "{b["name"]}"')
        lines.append("")

    if branch_findings.get("stale"):
        lines.append("# === Delete stale branches (review carefully!) ===")
        for b in branch_findings["stale"]:
            lines.append(f'# Stale {b["days_old"]} days, last: {b["last_subject"][:50]}')
            if force_delete:
                lines.append(f'git branch -D "{b["name"]}"')
            else:
                lines.append(f'# git branch -D "{b["name"]}"  # Uncomment after review')
        lines.append("")

    lines.append("# === Optimize repo ===")
    lines.append("git gc --aggressive --prune=now")
    lines.append("")
    lines.append('echo "Cleanup complete!"')

    return "\n".join(lines)

Technical Analysis

The cleanup script includes the audited repository path only in a comment. Its destructive Git commands do not use git -C, and the script does not change its working directory to the audited repository.

Git therefore operates on whichever repository is associated with the process's current working directory when the script is executed. Branch names and classifications we ...[truncated 1513 chars]

Remediation
View remediation

Remediation Suggestions

  • Resolve and record the audited repository's canonical path when generating the script.
  • Bind every Git operation to that path using safely quoted commands such as git -C "$repo" branch ... and git -C "$repo" gc ....
  • Add a preflight check using git -C "$repo" rev-parse --show-toplevel and terminate if it does not match the expected canonical repository path.
  • Do not rely on the caller's current working directory.
  • Require explicit confirmation before forced branch deletion or immediate object pruning.
  • Avoid --prune=now by default; retain Git's normal grace period unless the user explicitly requests irreversible pruning.
  • Include repository identity information, such as the canonical path and expected HEAD object ID, and verify it before making changes.
  • Add integration tests that generate a script for one repository and execute it from another, confirming that only the audited repository can be modified.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • 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 (12)

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding

The code substantially matches the core declared purpose of auditing git repositories for stale/merged branches, large files, repo health, and generating a cleanup script. However, there is a meaningful description/behavior gap: the declared description explicitly includes finding orphaned tags, but the code only counts tags and never analyzes or identifies orphaned tags. In addition, the generated cleanup script is limited to deleting branches and running git gc; it does not provide cleanup steps for large files in history or tag cleanup, which makes the 'generate cleanup scripts' claim somewhat broader than the implementation. This is a partial mismatch rather than a wholly different purpose.

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 13)May include surrounding context.

md
python3 scripts/audit_repo.py /path/to/repo

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/audit_repo.py /path/to/repo

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/audit_repo.py /path/to/repo

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/audit_repo.py /path/to/repo

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/audit_repo.py /path/to/repo

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
python3 scripts/audit_repo.py /path/to/repo

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/audit_repo.py (reported line 321)May include surrounding context.

python
common_ignores = {
        "node_modules": "Node.js dependencies",
        "__pycache__": "Python bytecode cache",
        ".env": "Environment variables (may contain secrets)",
        ".DS_Store": "macOS folder metadata",
        "Thumbs.db": "Windows thumbnail cache",
        "*.pyc": "Python compiled files",

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
88% confidence
Finding

The skill invokes Python scripts against arbitrary repository paths and therefore implies file-read and shell-like execution capability, but it does not declare any tool scope or permissions boundaries. In an agent environment, missing scope declarations can cause the skill to be invoked with broader-than-expected access, increasing the chance of unintended repository inspection or unsafe command generation.

Content

No source excerpt is available for this finding.

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
90% confidence
Finding

The manifest description says to use the skill when asked to "clean up a git repo" or perform "repo maintenance," and also lists trigger phrases like "merged branches" and "git audit." Several of these are broad enough to match ordinary conversation about Git repositories without clearly constraining when this skill should or should not activate.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill description advertises generating cleanup scripts with both safe delete and force-delete options, which can affect repository state and potentially remove branches. The markdown does not include any explicit warning about reviewing generated scripts, data loss risk, or the implications of force deletion.

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

python
def run_git(repo_path, *args, check=False):
    """Run a git command and return stdout."""
    try:
        result = subprocess.run(
            ["git", "-C", str(repo_path)] + list(args),
            capture_output=True, text=True, timeout=30
        )