Back to skill

Security audit

Storage Cleanup

Security checks for vulnerabilities and agentic risk

Overview

This storage cleanup skill is purpose-aligned, but its script can delete user and system resources immediately and sometimes with sudo despite documentation implying safer confirmation behavior.

Review before installing or running. Use only `bash scripts/cleanup.sh --dry-run` first, avoid running it without arguments, and skip high-impact categories such as kernels, Docker, snaps, and Homebrew unless you explicitly want those resources removed. The package is not evidence of exfiltration or persistence, but it can cause real data loss or system changes.

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/cleanup.sh:10
Finding
Destructive Cleanup Executes by Default Without Confirmation## Vulnerability Details **File Location**: `scripts/cleanup.sh:10-15`, `scripts/cleanup.sh:22-28`, `scripts/cleanup.sh:104-112`; conflicting claims in `SKILL.md:8-16` **Vulnerability Type**: Unsafe destructive default and ineffective confirmation control **Risk Level**: High ### Vulnerable Code ```bash DRY_RUN=false SKIP_KERNELS=false SKIP_SNAP=false SKIP_DOCKER=false SKIP_BREW=false AUTO_YES=false ``` ```bash for arg in "$@"; do case "$arg" in --dry-run) DRY_RUN=true ;; --skip-kernels) SKIP_KERNELS=true ;; --skip-snap) SKIP_SNAP=true ;; --skip-docker) SKIP_DOCKER=true ;; --skip-brew) SKIP_BREW=true ;; --yes|-y) AUTO_YES=true ;; ``` ```bash do_clean() { local desc="$1" shift if $DRY_RUN; then echo "[DRY-RUN] Would: $desc" else echo "Cleaning: $desc" "$@" 2>/dev/null || true fi } ``` ### Technical Analysis The script initializes `DRY_RUN` to `false`, so invoking it without arguments enables destructive operations immediately. Although it parses `--yes` into `AUTO_YES`, that variable is never consulted before cleanup begins. There is also no interactive confirmation prompt. This behavior conflicts with the documentation's claims that the Skill is “safe by default” and that dry-run mode protects users from unintended changes. The implementation instead requires users to explicitly request safety with `--dry-run`. The generic `do_clean` function executes every supplied deletion or cleanup command whenever `DRY_RUN` is false. This includes `rm -rf`, package cleanup, journal vacuuming, snap removal, Docker pruning, and kernel package removal. Several Linux operations invoke `sudo`, increasing the affected scope from user-owned files to system resources. Errors are suppressed through `2>/dev/null || true`, which can also conceal partial failures and make it difficult for users to determine exactly which destruct ...[truncated 1717 chars]
Remediation
## Remediation Suggestions 1. Make dry-run behavior the default: ```bash DRY_RUN=true ``` 2. Require explicit authorization before enabling destructive mode: ```bash --yes|-y) AUTO_YES=true DRY_RUN=false ;; ``` 3. If neither `--dry-run` nor `--yes` is supplied, show the planned operations and require an interactive confirmation. Abort when standard input is not an interactive terminal. 4. Check `AUTO_YES` before the first destructive operation rather than merely parsing it. 5. Use separate opt-in flags for high-impact categories such as kernels, Docker, Xcode archives, snaps, and system logs. These should not be included in a generic default cleanup. 6. Avoid blanket error suppression. Log command failures and return a nonzero status when critical cleanup operations fail. 7. Update `SKILL.md` so the documented default behavior precisely matches the implementation and clearly identifies operations requiring `sudo`.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/cleanup.sh:238
Finding
Cleanup Deletes Resources Beyond the Documented Scope## Vulnerability Details **File Location**: `scripts/cleanup.sh:238-269`, `scripts/cleanup.sh:343-348`; scope descriptions in `SKILL.md:50`, `SKILL.md:62-64` **Vulnerability Type**: Overbroad destructive file and resource cleanup **Risk Level**: Medium ### Vulnerable Code ```bash # Xcode Archives (old builds) ARCHIVES="$HOME/Library/Developer/Xcode/Archives" if [ -d "$ARCHIVES" ]; then size=$(get_dir_bytes "$ARCHIVES") if (( size > 104857600 )); then echo "Xcode Archives: $(bytes_to_human $size)" do_clean "Clear Xcode Archives" rm -rf "$ARCHIVES"/* fi fi # iOS Device Support DEVICE_SUPPORT="$HOME/Library/Developer/Xcode/iOS DeviceSupport" if [ -d "$DEVICE_SUPPORT" ]; then size=$(get_dir_bytes "$DEVICE_SUPPORT") if (( size > 524288000 )); then echo "iOS DeviceSupport: $(bytes_to_human $size)" do_clean "Clear iOS DeviceSupport" rm -rf "$DEVICE_SUPPORT"/* fi fi ``` ```bash if ! $SKIP_DOCKER && command -v docker &>/dev/null; then section "Docker" docker system df 2>/dev/null || true do_clean "Prune dangling Docker images and build cache" docker system prune -f fi ``` ### Technical Analysis The documentation describes Xcode archives and device support as “old” artifacts, but the implementation does not apply an age, version, or usage filter. Once the directory exceeds its size threshold, `rm -rf "$ARCHIVES"/*` and `rm -rf "$DEVICE_SUPPORT"/*` remove every non-hidden entry. The threshold determines whether cleanup occurs; it does not restrict which entries are deleted. The Docker description says the script removes only unreferenced or dangling images and build cache. However, `docker system prune -f` has a broader scope: it can remove stopped containers, unused networks, dangling images, and unused build cache. Thus, the displayed description understates the actual operation. Quoting the parent directory variables prevents ordinary shell w ...[truncated 1755 chars]
Remediation
## Remediation Suggestions 1. Apply explicit age filters to Xcode archives instead of deleting every entry. For example, enumerate archives older than a documented retention period and show each candidate during dry-run. 2. Retain recent archives and allow users to configure the retention period. Require a separate explicit flag before removing all archives. 3. Determine installed or required iOS device-support versions and remove only versions that are demonstrably obsolete. If reliable detection is unavailable, list candidates and require per-version confirmation. 4. Replace the broad Docker command with narrowly scoped commands consistent with the description, such as separately pruning dangling images and build cache. 5. If `docker system prune` remains necessary, accurately disclose that it may remove stopped containers and unused networks, and require a dedicated opt-in flag and confirmation. 6. Display an exact resource list before deletion and record the result of each operation. 7. Add tests that compare documented cleanup categories with the actual command scope, including tests proving that recent Xcode archives and stopped Docker containers are retained under default settings.
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (23)

Tool Parameter Abuse

High
Category
Tool Misuse
Content
TRASH_SIZE=$(get_dir_bytes "$TRASH_DIR")
  echo "Trash size: $(bytes_to_human $TRASH_SIZE)"
  if $IS_MAC; then
    do_clean "Empty trash" rm -rf "$HOME/.Trash/"*
  else
    do_clean "Empty trash" rm -rf "$TRASH_DIR/files/"* "$TRASH_DIR/info/"*
  fi
Confidence
95% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
if $IS_MAC; then
    do_clean "Empty trash" rm -rf "$HOME/.Trash/"*
  else
    do_clean "Empty trash" rm -rf "$TRASH_DIR/files/"* "$TRASH_DIR/info/"*
  fi
else
  echo "Trash is empty"
Confidence
95% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
size=$(get_dir_bytes "$DERIVED")
    if (( size > 104857600 )); then
      echo "Xcode DerivedData: $(bytes_to_human $size)"
      do_clean "Clear Xcode DerivedData" rm -rf "$DERIVED"/*
    fi
  fi
Confidence
95% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
size=$(get_dir_bytes "$ARCHIVES")
    if (( size > 104857600 )); then
      echo "Xcode Archives: $(bytes_to_human $size)"
      do_clean "Clear Xcode Archives" rm -rf "$ARCHIVES"/*
    fi
  fi
Confidence
95% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
size=$(get_dir_bytes "$DEVICE_SUPPORT")
    if (( size > 524288000 )); then
      echo "iOS DeviceSupport: $(bytes_to_human $size)"
      do_clean "Clear iOS DeviceSupport" rm -rf "$DEVICE_SUPPORT"/*
    fi
  fi
Confidence
95% 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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
size=$(get_dir_bytes "$SIMULATORS")
    if (( size > 104857600 )); then
      echo "CoreSimulator Caches: $(bytes_to_human $size)"
      do_clean "Clear CoreSimulator caches" rm -rf "$SIMULATORS"/*
    fi
  fi
Confidence
95% 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).

Chaining Abuse

High
Category
Tool Misuse
Content
echo "Old kernels found:"
    echo "$OLD_KERNELS"
    if ! $DRY_RUN; then
      echo "$OLD_KERNELS" | xargs sudo apt purge -y 2>&1 || true
      sudo apt autoremove -y 2>&1 || true
    else
      echo "[DRY-RUN] Would purge old kernels"
Confidence
89% confidence
Finding
The pipeline into 'xargs sudo apt purge -y' chains auto-discovered package names directly into a privileged destructive command. Because the selection logic for 'OLD_KERNELS' is heuristic and non-empty output is acted on automatically, a misclassification can turn routine cleanup into removal of essential boot packages with system-wide availability impact.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
| Flag | Effect |
|------|--------|
| `--dry-run` | Preview cleanup without deleting anything |
| `--yes` / `-y` | Run without confirmation prompts |
| `--skip-kernels` | Don't remove old kernels (Linux) |
| `--skip-snap` | Don't remove disabled snap revisions (Linux) |
| `--skip-docker` | Don't prune Docker |
Confidence
75% 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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- **Ollama models**: `ollama list` → `ollama rm <unused>`
- **npm global cache**: `npm cache clean --force`
- **Conda envs**: `conda env list` → `conda remove -n <env> --all`
- **Compressed logs**: `sudo find /var/log -name "*.gz" -delete`
- **Flatpak** (Linux): `flatpak uninstall --unused`
- **Time Machine snapshots** (macOS): `tmutil listlocalsnapshots /` → `tmutil deletelocalsnapshots <date>`
Confidence
70% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
echo "  --skip-snap     Skip disabled snap revision removal (Linux only)"
      echo "  --skip-docker   Skip Docker cleanup"
      echo "  --skip-brew     Skip Homebrew cleanup (macOS)"
      echo "  --yes, -y       Skip confirmation prompts"
      exit 0 ;;
  esac
done
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.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
maybe_sudo() {
  if $IS_MAC; then
    # Most macOS cleanup doesn't need sudo
    "$@"
  else
    sudo "$@"
Confidence
50% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "/tmp size: $(bytes_to_human $TMP_SIZE)"
  if (( TMP_SIZE > 104857600 )); then
    do_clean "Remove stale pip/build dirs from /tmp" bash -c '
      sudo find /tmp -maxdepth 1 -name "pip-*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
      sudo find /tmp -maxdepth 1 -name "npm-*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
      sudo find /tmp -maxdepth 1 -name "rust_*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
    '
Confidence
87% confidence
Finding
This line performs privileged deletion in /tmp using broad filename patterns and 'rm -rf'. On multi-user systems, '/tmp' is a shared namespace, so the script may delete other users' or active processes' temporary directories if they happen to match these patterns and are older than 60 minutes, causing data loss or service disruption.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
if (( TMP_SIZE > 104857600 )); then
    do_clean "Remove stale pip/build dirs from /tmp" bash -c '
      sudo find /tmp -maxdepth 1 -name "pip-*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
      sudo find /tmp -maxdepth 1 -name "npm-*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
      sudo find /tmp -maxdepth 1 -name "rust_*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
    '
  fi
Confidence
87% confidence
Finding
This privileged 'find ... -exec rm -rf' removes '/tmp/npm-*' directories solely by age and name. In a shared temp area that can impact unrelated users or applications and can break currently needed build artifacts or sessions.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
do_clean "Remove stale pip/build dirs from /tmp" bash -c '
      sudo find /tmp -maxdepth 1 -name "pip-*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
      sudo find /tmp -maxdepth 1 -name "npm-*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
      sudo find /tmp -maxdepth 1 -name "rust_*" -type d -mmin +60 -exec rm -rf {} + 2>/dev/null
    '
  fi
fi
Confidence
87% confidence
Finding
This line deletes '/tmp/rust_*' directories as root based only on naming and age. The broad privileged deletion creates a real integrity/availability risk because it can remove legitimate temporary data outside the caller's ownership.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "Old kernels found:"
    echo "$OLD_KERNELS"
    if ! $DRY_RUN; then
      echo "$OLD_KERNELS" | xargs sudo apt purge -y 2>&1 || true
      sudo apt autoremove -y 2>&1 || true
    else
      echo "[DRY-RUN] Would purge old kernels"
Confidence
88% confidence
Finding
This line pipes package names into 'xargs sudo apt purge -y' without robust validation of the package set. The old-kernel detection heuristic is brittle and can purge packages based on partial string filtering, risking accidental removal of needed kernels and leaving the system unbootable after reboot.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
echo "$OLD_KERNELS"
    if ! $DRY_RUN; then
      echo "$OLD_KERNELS" | xargs sudo apt purge -y 2>&1 || true
      sudo apt autoremove -y 2>&1 || true
    else
      echo "[DRY-RUN] Would purge old kernels"
    fi
Confidence
83% confidence
Finding
Following the purge with unconditional 'sudo apt autoremove -y' can remove additional dependencies automatically, compounding mistakes from incorrect kernel selection. If the prior package set is wrong, autoremove increases the blast radius and may strip required boot components.

Static analysis

No suspicious patterns detected.