Back to skill

Security audit

Genie

Security checks for vulnerabilities and agentic risk

Overview

This is a legitimate disk-cleanup skill, but it needs Review because it can delete broad local data, update itself from GitHub, and includes database-changing helpers beyond its stated read-only database scope.

Review carefully before installing on production or shared systems. Run dry-run first, disable or tightly scope /tmp and snapshot cleanup unless explicitly needed, avoid silent self-updates without a trusted release process, and treat database rebuild/repair helpers as separate manual maintenance steps requiring explicit approval and backups.

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/genie.py:991
Finding
Snapshot deletion bypasses the documented user-confirmation gate## Vulnerability Details **File Location**: `scripts/genie.py:991-1023`, invoked from `scripts/genie.py:1770-1774` and `scripts/genie.py:1926-1932` **Vulnerability Type**: Destructive operation without code-enforced confirmation **Risk Level**: High ### Technical Analysis The cleanup implementation automatically deletes older rollback snapshots when their age exceeds the configured threshold: ```python def clean_snapshots(snapshots_path, max_age_days, dry_run): result = {"action": "snapshots", "tier": 1, "files": 0, "bytes_freed": 0, "errors": []} if not os.path.isdir(snapshots_path): return result # Find the most recent snapshot (by oldest mtime inside dir) — always preserved entries = [] for entry in os.listdir(snapshots_path): path = os.path.join(snapshots_path, entry) if not os.path.isdir(path): continue oldest = oldest_mtime_in_dir(path) entries.append((oldest, entry, path)) if not entries: return result # Skip the most recent snapshot (highest mtime = youngest) entries.sort(key=lambda x: x[0], reverse=True) most_recent_path = entries[0][2] result["skipped_most_recent"] = os.path.basename(most_recent_path) for oldest, entry, path in entries: if path == most_recent_path: continue snap_age = (datetime.datetime.now().timestamp() - oldest) / 86400 if snap_age > max_age_days: size = du(path) result["files"] += 1 result["bytes_freed"] += size if not dry_run: try: shutil.rmtree(path) ``` The normal cleanup workflow invokes this operation unconditionally: ```python def clean(cfg): tier_limit = int(cfg.get("tier_limit", 3)) results = [] results.append(clean_snapshots( cfg["snapshots_path"], cfg["snapshot_max_age_days"], ...[truncated 1939 chars]
Remediation
## Remediation Suggestions - Default snapshot handling to report-only or dry-run mode. - Require a dedicated flag such as `--confirm-snapshot-deletion` before any snapshot can be removed. - Bind confirmation to the exact snapshot paths displayed during assessment, preventing configuration changes between assessment and deletion from expanding the approved scope. - If emergency deletion is supported, verify the documented emergency condition in code, such as 100% root-filesystem utilization, and clearly record that the emergency bypass was used. - Reject non-interactive snapshot deletion unless a machine-verifiable approval token or explicit automation policy is supplied. - Log each deleted path, size, timestamp, and confirmation mechanism instead of reporting only aggregate reclaimed space. - Preserve the existing newest-snapshot protection and add regression tests proving that `--clean` alone cannot delete snapshots.

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/genie.py:1417
Finding
Age-only recursive cleanup of shared /tmp crosses user and service boundaries## Vulnerability Details **File Location**: `scripts/genie.py:1417-1440`, invoked from `scripts/genie.py:1793-1795` **Vulnerability Type**: Unsafe shared temporary-directory cleanup **Risk Level**: Medium ### Technical Analysis The cleanup function enumerates every top-level entry under the supplied temporary directory and recursively deletes entries based solely on their modification age: ```python def clean_tmp(tmp_path, max_age_hours, dry_run): result = {"action": "tmp", "tier": 1, "files": 0, "bytes_freed": 0, "errors": []} if not os.path.isdir(tmp_path): return result for entry in os.listdir(tmp_path): path = os.path.join(tmp_path, entry) # Skip if still in use (check if any process has it open would be ideal, # but for safety we just check age) if age_hours(path) > max_age_hours: size = du(path) result["files"] += 1 result["bytes_freed"] += size if not dry_run: try: if os.path.isdir(path): shutil.rmtree(path) else: os.remove(path) except Exception as e: result["errors"].append(f"remove {path}: {e}") result["bytes_freed"] -= size return result ``` The main cleanup workflow always supplies the system-wide `/tmp` directory when temporary cleanup is enabled: ```python # /tmp if cfg.get("tmp_stale_hours", 0) > 0: results.append(clean_tmp( "/tmp", cfg["tmp_stale_hours"], cfg["dry_run"] )) ``` The default threshold is 24 hours. The implementation does not restrict deletion to Skill-owned or application-specific names, verify ownership, test whether an entry is a mount point, or determine whether another process is using the entry. A top-level directory’s mtime only reflects changes to ...[truncated 1963 chars]
Remediation
## Remediation Suggestions - Replace whole-directory `/tmp` enumeration with an allowlist of application-specific patterns documented by the Skill. - Require expected ownership and reject entries owned by other users unless the operator explicitly approves each path. - Refuse to traverse or delete mount points and apply no-follow filesystem operations where supported. - Check for active process references before deletion, such as open file descriptors or application-specific process detection. - Evaluate activity recursively or use application-generated cleanup markers rather than relying on the top-level directory mtime. - Present candidate paths during assessment and require explicit confirmation for entries outside a narrowly defined safe allowlist. - Prefer a system temporary-file manager with ownership, age, and exclusion policies over custom recursive deletion. - Add regression tests covering foreign-owned entries, active files, symlinks, and nested mount points.
Vulnerability Patterns
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • Tool MisuseTool Parameter Abuse, Chaining Abuse, Unsafe Defaults
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (77)

Self-Modification

High
Category
Rogue Agent
Content
## [1.1.0] - 2026-05-23

### Added
- OCAS architecture compliance: Responsibility Boundary, Ontology Types, Journal Outputs, Storage Layout, OKRs, Background Tasks, Initialization, and Self-update sections
- `skill.json` with ConfigBase fields and self-update configuration
- `.gitignore` for skill package
- README.md and CHANGELOG.md
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Self-Modification

High
Category
Rogue Agent
Content
## [1.1.0] - 2026-05-23

### Added
- OCAS architecture compliance: Responsibility Boundary, Ontology Types, Journal Outputs, Storage Layout, OKRs, Background Tasks, Initialization, and Self-update sections
- `skill.json` with ConfigBase fields and self-update configuration
- `.gitignore` for skill package
- README.md and CHANGELOG.md
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Self-Modification

High
Category
Rogue Agent
Content
### Added
- OCAS architecture compliance: Responsibility Boundary, Ontology Types, Journal Outputs, Storage Layout, OKRs, Background Tasks, Initialization, and Self-update sections
- `skill.json` with ConfigBase fields and self-update configuration
- `.gitignore` for skill package
- README.md and CHANGELOG.md
- `genie:update` cron job for daily self-updates from GitHub
Confidence
94% confidence
Finding
A 'skill.json' self-update configuration strongly suggests built-in support for modifying or replacing the skill after deployment. Self-modification is high risk because it undermines code immutability, complicates review, and can enable supply-chain compromise, especially for a filesystem-maintenance skill with elevated access.

Self-Modification

High
Category
Rogue Agent
Content
- `skill.json` with ConfigBase fields and self-update configuration
- `.gitignore` for skill package
- README.md and CHANGELOG.md
- `genie:update` cron job for daily self-updates from GitHub
- `genie:weekly-cleanup` cron job registration during initialization

### Changed
Confidence
97% confidence
Finding
A cron job for daily self-updates from GitHub combines persistence with self-modification, creating a clear path for unattended code replacement. In the context of a disk cleanup skill that may operate with broad local access, this materially raises the risk of supply-chain compromise and unauthorized actions over time.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented purpose is disk auditing/cleanup, but the finding indicates associated code can modify SQLite schema and rebuild application database structures. That exceeds the stated maintenance scope and could alter live application state under the guise of disk cleanup, creating integrity and availability risk. Context makes this worse because the skill repeatedly claims safety while operating near critical state databases.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documented purpose is disk auditing/cleanup, but the finding indicates associated code can modify SQLite schema and rebuild application database structures. That exceeds the stated maintenance scope and could alter live application state under the guise of disk cleanup, creating integrity and availability risk. Context makes this worse because the skill repeatedly claims safety while operating near critical state databases.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
description: "Compress session JSONs older than N days"
        default: "14"
      - key: genie.tmp_stale_hours
        description: "Delete /tmp files older than N hours (0 to skip)"
        default: "24"
      - key: genie.git_clone_max_age_days
        description: "Delete git clones in <projects-root>/ untouched for N days (must have remote)"
Confidence
84% confidence
Finding
Deleting files from `/tmp` based solely on age is a classic high-risk cleanup pattern because active or needed temporary artifacts can persist longer than expected or be used by running jobs. The skill does mention some process checks elsewhere, but broad age-based deletion remains error-prone without strong ownership, path, and liveness validation. In incident conditions on a VPS, this can disrupt services or destroy forensic artifacts.

Ae1

High
Category
analysis-evasion
Content
rvived. Verify the snapshot dir directly (see Verification). Fix is pending in `scripts/genie.py`; until then, treat snapshot preservation as UNVERIFIED after a
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
rvived. Verify the snapshot dir directly (see Verification). Fix is pending in `scripts/genie.py`; until then, treat snapshot preservation as UNVERIFIED after a
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
rvived. Verify the snapshot dir directly (see Verification). Fix is pending in `scripts/genie.py`; until then, treat snapshot preservation as UNVERIFIED after a
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Tool Parameter Abuse

High
Category
Tool Misuse
Content
- **Needs sync first:** dirty or `ahead>0`. Commit → push → re-verify `dirty==0 && ahead==0` → only then `rm -rf`. Never delete before the remote actually has the commit.
- **Exclude:** stale mirrors (local clone older/smaller than the live source, e.g. `indigo-repo` 104 vs live 141 skills) and protected live-skill directories. For a stale mirror where local HEAD == remote HEAD, a local-only delete is safe (GitHub holds the commit; live skills live elsewhere) — but a daily skill-sync may recreate it.

Blockers that prevent a clean sync: dead local `origin` remote → repush to the real GitHub remote; nested git repo / submodule → sync the nested repo then pin the parent gitlink; pull-rebase conflict on a stale mirror → `git reset --hard origin/main` (remote supercedes — ONLY for disposable mirror clones; NEVER in a live skill dir, where divergence must refuse loudly and be reconciled with an explicit rebase); husky pre-push test stalls → do **NOT** bypass the hook, diagnose/fix the suite or drop the clone after user confirms.

## Configuration
Confidence
88% confidence
Finding
The skill recommends use of `git reset --hard origin/main` in some scenarios, which is a destructive command that discards local changes. Even though the text tries to limit usage to disposable mirrors, agents may misclassify repositories or execute in the wrong path, causing permanent loss of uncommitted work. In a skill already empowered to delete clones, this materially increases destructive potential.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
| `log_delete_age_days` | 30 | Delete compressed logs older than N days |
| `cron_output_compress_age_days` | 7 | Compress cron output files older than N days |
| `session_compress_age_days` | 14 | Compress session JSONs older than N days |
| `tmp_stale_hours` | 24 | Delete /tmp files older than N hours (0 to skip) |
| `git_clone_max_age_days` | 5 | Delete git clones in <projects-root>/ untouched for N days (must have remote) |
| `dry_run` | false | If true, only report — don't delete/compress |
| `filesystem_md` | (empty) | Optional override path for FILESYSTEM.md |
Confidence
84% confidence
Finding
This is the same risky `/tmp` deletion capability expressed in the configuration table. Exposing it as a configurable retention control can normalize unsafe deletion and widen its use without requiring case-by-case validation. Because the skill is designed to run during disk pressure, operators may enable aggressive cleanup that harms active workloads.

Ae1

High
Category
analysis-evasion
Content
| `references/repo-path-conventions.md` | Repo path convention — all remote clones under `projects/github*` |
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Intent-Code Divergence

High
Confidence
98% confidence
Finding
This is a true vulnerability signal: the documentation claimed clone-deletion safety gates existed, but the code did not enforce them. In a skill that performs disk cleanup and deletion of git clones, this mismatch can directly enable unsafe deletion of repositories containing unique local work such as unpushed commits, stashes, or modified files. The skill context makes this more dangerous because it is explicitly authorized to reclaim disk space and may be run during operational pressure, increasing the chance that operators trust the documented safeguards and invoke destructive cleanup.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Check if camoufox is in use before deleting
ps aux | grep camoufox
rm -rf /tmp/camoufox-*
```

## Large Caches Not Tracked by Package Managers
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).

Tool Parameter Abuse

High
Category
Tool Misuse
Content
```bash
# Check if camoufox is in use before deleting
ps aux | grep camoufox
rm -rf /tmp/camoufox-*
```

## Large Caches Not Tracked by Package Managers
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).

Self-Modification

High
Category
Rogue Agent
Content
- **Large file counts**: With 5,000+ files to gzip, use `terminal(background=True, notify_on_complete=True)`.
- **Disk-at-100% blocks operations**: When disk is at 100%, Genie cannot write journal files, create temp files, or stage data. Check `df -h /` first — if at 100%, focus on immediate space recovery (Tier 1 cleanup, snapshot deletion) before attempting any backup workflow.
- **Script/version desync during self-update**: Always compare script hashes even when versions match. See `references/self-update-genie.md`.
- **`~` path resolution in cron context**: When running as a cron job, `HOME` is set to the profile-scoped path, not `<fs-root>/`. **Always use absolute paths** (`<hermes-home>/...`) in cron context.
- **GitHub default branch is `main`**: The genie repo's default branch is `main`, not `master`. Using `master` in raw GitHub URLs returns 404 or stale content.
- **Script path deduplication**: The three script paths in Step 0 may resolve to the same file (hardlink or symlink). `cp` between them will fail with "same file" — this is expected. Use `cmp` or `ls -i` (inode check) to verify before assuming they're independent copies.
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Self-Modification

High
Category
Rogue Agent
Content
- **Large file counts**: With 5,000+ files to gzip, use `terminal(background=True, notify_on_complete=True)`.
- **Disk-at-100% blocks operations**: When disk is at 100%, Genie cannot write journal files, create temp files, or stage data. Check `df -h /` first — if at 100%, focus on immediate space recovery (Tier 1 cleanup, snapshot deletion) before attempting any backup workflow.
- **Script/version desync during self-update**: Always compare script hashes even when versions match. See `references/self-update-genie.md`.
- **`~` path resolution in cron context**: When running as a cron job, `HOME` is set to the profile-scoped path, not `<fs-root>/`. **Always use absolute paths** (`<hermes-home>/...`) in cron context.
- **GitHub default branch is `main`**: The genie repo's default branch is `main`, not `master`. Using `master` in raw GitHub URLs returns 404 or stale content.
- **Script path deduplication**: The three script paths in Step 0 may resolve to the same file (hardlink or symlink). `cp` between them will fail with "same file" — this is expected. Use `cmp` or `ls -i` (inode check) to verify before assuming they're independent copies.
Confidence
90% confidence
Finding
Skill modifies its own code, configuration, or behavior at runtime. Self-modification enables an agent to escalate privileges, disable safety constraints, or install persistent backdoors.

Intent-Code Divergence

High
Confidence
98% confidence
Finding
This is a true vulnerability because the document explicitly describes a confirmed bug where retention logic can delete the most recent state snapshot despite a safety guarantee that it is never auto-deleted. In a disk-cleanup skill, snapshots are likely the last recovery point before destructive maintenance, so silently reclaiming them can directly cause irreversible data loss and undermine rollback and incident recovery.

Context-Inappropriate Capability

High
Confidence
96% confidence
Finding
This section explicitly enables modifying repositories and pushing to remote services as part of a disk cleanup flow, including rebases, parent/nested repo synchronization, and LFS operations. In the context of a VPS cleanup skill, remote write access is over-privileged and dangerous because a mistaken target, stale branch, or sensitive local clone could cause unauthorized code publication or destructive repository state changes.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
|---|---|---|
| Dead local `origin` | `origin` = `/root/Graze` (not a repo); push → "Could not read from remote" | The real GitHub upstream is often present under a misnamed remote (`github`, `nithub`). `git push <real-remote> <branch>` instead of `origin`. |
| Nested git repo / submodule | Parent shows ` M subrepo`; `git add -A` won't stage it | The nested dir is a separate repo (e.g. `headhunter` = `util-head-hunter`). Sync the nested repo (`add/commit/push` to ITS remote), then commit the parent gitlink + `git pull --rebase` + push parent. No `.gitmodules` needed if already a gitlink (`160000` mode in `git ls-files --stage`). |
| Pull-rebase conflict on stale mirror | `git pull --rebase` stops on a conflict (e.g. README) | If the clone is a stale mirror superceded by remote (remote has many newer sanitize/beautify commits, both SKILL.md same version, live skill is source of truth), `git reset --hard origin/main` then delete. Confirm with user before discarding local commits. |
| Husky pre-push test stalls | push → "pre-push script failed (code 1)" or the test hangs past timeout | **Do NOT** `--no-verify`. The hook is a real CI gate. Diagnose/fix the suite, or (after user confirms) drop the clone without pushing. |
| LFS pre-receive hook decline | "Try to push them with `git lfs push --all`" | Repo uses `.gitattributes` LFS filters (`*.db`, `*.lbug`, etc.). Either `git lfs push --all origin` or, for a stale mirror, local-only delete (GitHub already holds the commit). |
| Non-fast-forward (remote advanced) | push → "fetch first" | `git pull --rebase origin <branch>` (resolve any conflict per above) then push. |
Confidence
91% confidence
Finding
The documented use of `git reset --hard origin/main` is a destructive command that irreversibly discards local commits and working-tree changes. Even though the text says to confirm with the user, embedding this in an automated pruning playbook raises the chance of operator or agent misuse, especially when combined with stale-mirror heuristics that may be wrong or incomplete.

Description-Behavior Mismatch

High
Confidence
97% confidence
Finding
These notes document backup, restore, VACUUM, and FTS rebuild workflows on large databases, directly contradicting the manifest statement that database work is limited to read-only analysis. That mismatch is dangerous because it broadens the effective authority of the skill into destructive or integrity-sensitive DB maintenance that could corrupt data, consume resources, or alter evidence without the operator expecting it.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
3. **backups/ is the biggest space consumer after snapshots**: The `backups/` directory accumulates multi-GB artifacts from operations (pre-update backups, DB dumps, skill clones). Genie does NOT scan `backups/` — it only handles `state-snapshots/`. A full cleanup workflow must include `backups/` inspection.

4. **Package caches (.cache/, .npm/) are significant**: Combined 1.3 GB of rebuildable caches. `npm cache clean --force` is more reliable than manual `rm -rf` for npm. Always run both `npm cache clean --force` AND `rm -rf ~/.cache/pip/* ~/.cache/uv/*`.

5. **Chrome temp dirs accumulate in /tmp/**: Multiple `com.google.Chrome.*` directories from browser automation sessions. Safe to delete when Chrome is not running. Check with `pgrep -a chrome` first.
Confidence
90% confidence
Finding
Chaining multiple recursive deletions in one recommendation (`~/.cache/pip/* ~/.cache/uv/*`) compounds the chance of destructive mistakes and reduces operator visibility into what will be removed. In a disk-cleanup skill operating on live systems, this kind of guidance can easily be copied into tooling without sufficient path validation, turning cleanup into unsafe mass deletion.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
3. **backups/ is the biggest space consumer after snapshots**: The `backups/` directory accumulates multi-GB artifacts from operations (pre-update backups, DB dumps, skill clones). Genie does NOT scan `backups/` — it only handles `state-snapshots/`. A full cleanup workflow must include `backups/` inspection.

4. **Package caches (.cache/, .npm/) are significant**: Combined 1.3 GB of rebuildable caches. `npm cache clean --force` is more reliable than manual `rm -rf` for npm. Always run both `npm cache clean --force` AND `rm -rf ~/.cache/pip/* ~/.cache/uv/*`.

5. **Chrome temp dirs accumulate in /tmp/**: Multiple `com.google.Chrome.*` directories from browser automation sessions. Safe to delete when Chrome is not running. Check with `pgrep -a chrome` first.
Confidence
89% confidence
Finding
Chaining multiple recursive deletions in one recommendation (`~/.cache/pip/* ~/.cache/uv/*`) compounds the chance of destructive mistakes and reduces operator visibility into what will be removed. In a disk-cleanup skill operating on live systems, this kind of guidance can easily be copied into tooling without sufficient path validation, turning cleanup into unsafe mass deletion.

Tool Parameter Abuse

High
Category
Tool Misuse
Content
3. **backups/ is the biggest space consumer after snapshots**: The `backups/` directory accumulates multi-GB artifacts from operations (pre-update backups, DB dumps, skill clones). Genie does NOT scan `backups/` — it only handles `state-snapshots/`. A full cleanup workflow must include `backups/` inspection.

4. **Package caches (.cache/, .npm/) are significant**: Combined 1.3 GB of rebuildable caches. `npm cache clean --force` is more reliable than manual `rm -rf` for npm. Always run both `npm cache clean --force` AND `rm -rf ~/.cache/pip/* ~/.cache/uv/*`.

5. **Chrome temp dirs accumulate in /tmp/**: Multiple `com.google.Chrome.*` directories from browser automation sessions. Safe to delete when Chrome is not running. Check with `pgrep -a chrome` first.
Confidence
90% confidence
Finding
Chaining multiple recursive deletions in one recommendation (`~/.cache/pip/* ~/.cache/uv/*`) compounds the chance of destructive mistakes and reduces operator visibility into what will be removed. In a disk-cleanup skill operating on live systems, this kind of guidance can easily be copied into tooling without sufficient path validation, turning cleanup into unsafe mass deletion.

Static analysis

No suspicious patterns detected.