Back to skill

Security audit

Last-Login Janitor

Security checks for vulnerabilities and agentic risk

Overview

The skill is a coherent disk-cleanup scanner, but broad scans can execute Git-controlled helper code inside repositories it inspects, so it needs review before installation.

Install only if you are comfortable running a local cleanup scanner over chosen directories. Avoid scanning inherited or untrusted repositories unless isolated, because Git metadata in those repos may trigger helper execution under your account. Treat the generated rm and docker commands as suggestions only; review each path and keep the manifest in a non-sensitive location.

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/dev_janitor.py:84
Finding

Repository-controlled Git configuration can execute commands during scanning

Content
View full analysis

Vulnerability Details

File Location: scripts/dev_janitor.py, lines 84–96
Vulnerability Type: Command execution through untrusted Git repository configuration
Risk Level: High

Vulnerable Code

python
def git_state(repo):
    """(dirty, n_stashes, unpushed_branches, has_remote)"""
    def git(*args):
        try:
            r = subprocess.run(["git", "-C", str(repo), *args],
                               capture_output=True, text=True, timeout=10)
            return r.stdout if r.returncode == 0 else ""
        except Exception:
            return ""
    status = git("status", "--porcelain")

Technical Analysis

The scanner recursively discovers Git repositories and automatically executes git status within each one. Although subprocess.run correctly uses an argument array and does not invoke a shell, Git is itself an extensible command runner.

Repository-local Git configuration can define executable helpers such as core.fsmonitor. Operations including git status may invoke those helpers while inspecting the worktree. Consequently, treating a discovered repository as passive data is unsafe when its metadata may have been supplied or modified by an independent party.

The Skill explicitly supports broad scans of home directories, inherited machines, build servers, and collections of repositories. In these workflows, repository contents and .git/config cannot necessarily be assumed trustworthy. The implementation does not validate repository ownership or provenance, disable executable Git features, or isolate Git in a sandbox.

The path passed to Git is not vulnerable to ordinary shell metacharacter injection because arguments are supplied without shell=True. The vulnerability instead arises from Git interpreting attacker-controlled repository configuration and launching a configured helper.

Attack Path

  1. An attacker supplies, modifies, or leaves behind a Git reposito ...[truncated 1499 chars]
Remediation
View remediation

Remediation Suggestions

  • Do not run normal Git worktree operations against repositories of unknown provenance without isolation.
  • Execute repository inspection in a sandbox that denies network access, restricts filesystem access to the repository, and prevents access to user credentials.
  • Override executable Git configuration for every invocation, including disabling core.fsmonitor and other helper mechanisms rather than relying on the user's global configuration.
  • Use a controlled environment with a minimal PATH, sanitized Git-related environment variables, and isolated global/system Git configuration.
  • Validate that repositories and their metadata are owned by the expected user before invoking Git. Treat ownership checks as defense in depth, not as a substitute for disabling executable helpers.
  • Where practical, inspect required repository metadata directly with a non-executing parser instead of invoking Git commands that process worktree configuration.
  • Document that scanning inherited or externally supplied repositories requires sandboxing until the executable-helper exposure is removed.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • Behavioral ASTexec() Call, eval() Call, Dynamic Import
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
Findings (21)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/dev_janitor.py` | The scanner/classifier: finds artifacts, dates them, flags stale/protected, emits ranked report + cleanup manifest |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/dev_janitor.py` | The scanner/classifier: finds artifacts, dates them, flags stale/protected, emits ranked report + cleanup manifest |

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

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

md
| `scripts/dev_janitor.py` | The scanner/classifier: finds artifacts, dates them, flags stale/protected, emits ranked report + cleanup manifest |

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
| `scripts/dev_janitor.py` | The scanner/classifier: finds artifacts, dates them, flags stale/protected, emits ranked report + cleanup manifest |

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/cleanup-playbook.md (reported line 71)May include surrounding context.

md
- Build cache: `docker builder prune` - safe, often 10-50 GB on CI boxes.

### Caches (pip/npm/uv/poetry/go/hf)
- pip: `pip cache purge` or `rm -rf ~/.cache/pip` - always rebuildable.
- npm: `npm cache clean --force`.
- uv: `uv cache clean`.
- HF models: NOT always cheap - a 40 GB Llama re-download on slow/metered

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
85% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/cleanup-playbook.md (reported line 71)May include surrounding context.

md
- Build cache: `docker builder prune` - safe, often 10-50 GB on CI boxes.

### Caches (pip/npm/uv/poetry/go/hf)
- pip: `pip cache purge` or `rm -rf ~/.cache/pip` - always rebuildable.
- npm: `npm cache clean --force`.
- uv: `uv cache clean`.
- HF models: NOT always cheap - a 40 GB Llama re-download on slow/metered

Tool Parameter Abuse

High
Category
Tool Misuse
Confidence
90% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/cleanup-playbook.md (reported line 71)May include surrounding context.

md
- Build cache: `docker builder prune` - safe, often 10-50 GB on CI boxes.

### Caches (pip/npm/uv/poetry/go/hf)
- pip: `pip cache purge` or `rm -rf ~/.cache/pip` - always rebuildable.
- npm: `npm cache clean --force`.
- uv: `uv cache clean`.
- HF models: NOT always cheap - a 40 GB Llama re-download on slow/metered

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
97% confidence
Finding

The skill advertises shell, file_read, and file_write behavior but does not declare any explicit tool scope or permission boundaries. That makes the effective capability set ambiguous and can lead an agent framework to grant broader access than reviewers expect, which is risky for a skill that inventories files and emits cleanup commands affecting large parts of a developer machine.

Content

No source excerpt is available for this finding.

Autonomous Decision Making

Medium
Category
Excessive Agency
Confidence
85% confidence
Finding

Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Content

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

Include Docker (requires docker group membership), exclude model dirs

python3 scripts/dev_janitor.py scan ~/ --docker --skip ~/.cache/huggingface

Emit a ready-to-review cleanup manifest (NOT auto-executed)

python3 scripts/dev_janitor.py scan ~/dev --stale-days 365 --manifest cleanup.json

text

Session Persistence

Medium
Category
Rogue Agent
Confidence
60% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/cleanup-playbook.md (reported line 38)May include surrounding context.

md
- Safe delete = clean, fully pushed, stale beyond window. Re-clone cost is
  seconds-to-minutes; your fork/clone URL is in `git remote -v` - record it
  in the manifest before deleting.
- Before deleting a repo with local-only branches: `git bundle create
  ../$(basename $PWD).bundle --all` - 10 MB insurance for years.

### Python virtualenvs

Rp1

Medium
Category
MCP Rug Pull
Confidence
75% confidence
Finding

Docker image references without a specific tag (:latest is implicit) or digest (@sha256:...) can be silently replaced by a malicious image.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
85% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · references/cleanup-playbook.md (reported line 120)May include surrounding context.

docker ps -a --format '{{.Image}} {{.Status}}'

venv referenced by cron/systemd?

grep -rn "venv|virtualenv" /etc/systemd/ /etc/cron* ~/.crontab 2>/dev/null

text

## 6. Suggested cadence

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The script and CLI describe the tool as 'READ-ONLY', but --manifest writes attacker-influenced scan results to an arbitrary filesystem path. In an agent setting, misleading safety claims can cause operators or higher-level automation to grant broader trust than warranted, leading to unintended file creation or overwrite in sensitive locations accessible to the current user.

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

python
def git_last_commit(repo):
    try:
        out = subprocess.run(
            ["git", "-C", str(repo), "log", "-1", "--format=%ct"],
            capture_output=True, text=True, timeout=10)
        if out.returncode == 0 and out.stdout.strip():

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

python
"""(dirty, n_stashes, unpushed_branches, has_remote)"""
    def git(*args):
        try:
            r = subprocess.run(["git", "-C", str(repo), *args],
                               capture_output=True, text=True, timeout=10)
            return r.stdout if r.returncode == 0 else ""
        except Exception:

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

python
protected = True
            if not remote and not protected and commit_ts > 0:
                # local-only repo: commits could exist nowhere else
                n = subprocess.run(["git", "-C", str(repo), "rev-list",
                                    "--count", "HEAD"], capture_output=True,
                                   text=True)
                try:

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

python
def scan_docker(stale_ts, artifacts, progress):
    def dock(*args):
        r = subprocess.run(["docker", *args], capture_output=True, text=True,
                           timeout=60)
        if r.returncode != 0:
            raise RuntimeError(r.stderr.strip())

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

python
except (FileNotFoundError, RuntimeError, subprocess.TimeoutExpired) as e:
        print(f"[docker] unavailable: {e}", file=sys.stderr)
    try:
        vols = subprocess.run(
            ["docker", "volume", "ls", "-q"], capture_output=True, text=True,
            timeout=60).stdout.split()
        in_use = set()

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

python
timeout=60).stdout.split()
        in_use = set()
        try:
            out = subprocess.run(
                ["docker", "ps", "-a", "--format", "{{.Mounts}}"],
                capture_output=True, text=True, timeout=60).stdout
            in_use = {v.strip() for line in out.splitlines()

Tool Parameter Abuse

Low
Category
Tool Misuse
Confidence
15% confidence
Finding

Tool parameters are crafted to achieve unintended or unsafe behavior. Parameter abuse can bypass intended safety checks (e.g. shell=True, --force, dangerous glob patterns).

Content

Scanner excerpt · references/cleanup-playbook.md (reported line 66)May include surrounding context.

md
- Tagged but unused: `docker image prune -a --filter "until=720h"` after
  human review of the list.
- Volumes: `docker volume ls -f dangling=true`. A dangling volume may hold
  a DATABASE - list contents (`docker run --rm -v VOL:/data alpine ls /data`)
  before deleting. Never bulk-delete volumes.
- Build cache: `docker builder prune` - safe, often 10-50 GB on CI boxes.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
84% confidence
Finding

The tool presents itself as a safe scanner, yet it generates executable deletion commands in its report and manifest. In a cleanup-oriented skill context, that discrepancy increases the chance that an agent or user will copy, trust, or auto-consume those commands without adequate review, potentially causing destructive follow-on actions.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.