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## 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
## 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## 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
## 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.

Ae1

High
Category
analysis-evasion
Content
python3 scripts/audit_repo.py /path/to/repo
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/audit_repo.py /path/to/repo
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/audit_repo.py /path/to/repo
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/audit_repo.py /path/to/repo
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/audit_repo.py /path/to/repo
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python3 scripts/audit_repo.py /path/to/repo
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
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",
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Lp3

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.

Vague Triggers

Medium
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.

Missing User Warnings

Medium
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.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
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
        )
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Static analysis

No suspicious patterns detected.