Back to skill

Security audit

Git Stats

Security checks for vulnerabilities and agentic risk

Overview

This git statistics skill does what it says, but users should review it because it exposes contributor emails and its line-counting code can read through tracked symlinks outside the repository boundary.

Install only if you are comfortable with the skill reading tracked repository files and showing contributor names and emails from git history. Avoid running it on untrusted repositories unless LOC counting is skipped or the symlink handling is fixed, and treat JSON/text output as potentially containing personal or internal contact information.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • 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)

T05 · Unauthorized Access and Privilege Escalation

Warning
Location
scripts/git_stats.py:102
Finding
Tracked Symbolic Links Can Cause Out-of-Repository File Reads<![CDATA[ ## Vulnerability Details **File Location**: `scripts/git_stats.py`, lines 102–110 **Vulnerability Type**: Improper path containment and symbolic-link handling **Risk Level**: Medium ```python for f in lines: if not f: continue filepath = os.path.join(cwd, f) if not os.path.isfile(filepath): continue ext = os.path.splitext(f)[1].lower() or "(no ext)" try: with open(filepath, "r", errors="ignore") as fh: count = sum(1 for _ in fh) ``` ### Technical Analysis The LOC calculation obtains tracked paths from `git ls-files`, joins each path to the repository root, and opens the resulting filesystem path. Both `os.path.isfile()` and `open()` follow symbolic links. A Git repository can contain a tracked symbolic link whose target is outside the repository. The implementation does not reject symbolic links or verify that the resolved path remains beneath the resolved repository root. Consequently, analyzing an attacker-controlled repository can cause the process to read an arbitrary external file, provided the file is readable under the privileges of the user running the Skill. The file content is not directly printed. However, the code reads the complete target and incorporates its line count into the aggregated LOC results, creating an unauthorized file-access and limited information-disclosure condition. ### Attack Path 1. An attacker creates a Git repository containing a tracked symbolic link that points to a sensitive local path, such as a predictable configuration or credential file. 2. The attacker convinces a user or automated agent to analyze that repository with this Skill. 3. LOC counting runs by default because `--no-loc` is not enabled. 4. `git ls-files` returns the tracked symbolic-link path. 5. `os.path.isfile()` follows the link and accepts it when its target is a regular file. 6. `open()` follows the same link and reads the external target in full. 7. The target's line count is inclu ...[truncated 730 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Reject symbolic links before opening tracked paths: ```python if os.path.islink(filepath): continue ``` 2. Resolve both the repository root and candidate path, then enforce containment: ```python root_real = os.path.realpath(cwd) filepath_real = os.path.realpath(os.path.join(root_real, f)) try: if os.path.commonpath([root_real, filepath_real]) != root_real: continue except ValueError: continue ``` 3. Open only the validated resolved path and, where supported, use no-follow semantics to reduce time-of-check/time-of-use risks. 4. Prefer reading repository blob data through Git, such as `git show HEAD:<path>` or an equivalent plumbing command. This counts the versioned object rather than following working-tree links and better matches the stated purpose of analyzing tracked repository content. 5. Add regression tests covering: - A tracked symlink to a file outside the repository. - A tracked symlink to a directory outside the repository. - Nested paths that resolve outside the repository. - Ordinary tracked files that remain within the repository. ]]>
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
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill invokes local code and shell-accessed functionality (`python3 scripts/git_stats.py`, `git`) but does not declare any tool scope such as `permissions` or `allowed-tools`. That creates ambiguity about what the skill is permitted to access and increases the chance an agent could run it with broader-than-necessary file read or shell privileges.

Vague Triggers

Medium
Confidence
91% confidence
Finding
The description uses broad activation phrases such as analyzing repos, showing git stats, contributor info, and counting lines of code, which can match many common user requests. Over-broad triggering can cause the skill to activate unexpectedly and perform shell/file operations in contexts where the user did not clearly intend repository analysis.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The documented output explicitly includes contributor rankings with email addresses from git history, but there is no warning that this may expose personal or sensitive information. In shared environments, logs, screenshots, or downstream JSON processing, the skill could disclose contributor email addresses without the user's awareness.

subprocess module call

Medium
Category
Dangerous Code Execution
Content
def run_git(args, cwd=None):
    """Run a git command and return stdout lines."""
    try:
        result = subprocess.run(
            ["git"] + args,
            capture_output=True,
            text=True,
Confidence
70% confidence
Finding
subprocess module calls execute external commands. Without careful input validation, this enables command injection.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The tool enumerates contributor names and email addresses and prints them by default in both text and JSON output, which can expose personal or internal contact information from repository history. In the skill context, this is more dangerous because repository analytics are likely to be shared, pasted into chats, or run against private enterprise repositories where author emails may be sensitive.

Static analysis

No suspicious patterns detected.