Back to skill

Security audit

净盘师 DiskKeeper

Security checks for vulnerabilities and agentic risk

Overview

This local Windows disk-cleaning skill is purpose-aligned, but it needs Review because some deletion paths are broader and more irreversible than the safety claims suggest.

Install only if you are comfortable reviewing cleanup plans manually. Run plan or clean without --yes first, avoid running it as administrator, do not use recycle --purge unless you intend to permanently empty the entire recycle bin, and do not configure unattended cleanup until deletion roots are strictly allowlisted and audit failures are fixed.

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/disk_butler.py:89
Finding
Environment-Controlled Cleanup Roots Can Cause Deletion Outside Trusted Cache Locations<![CDATA[ ## Vulnerability Details **File Location**: `scripts/disk_butler.py`, lines 89–96, 357–381, and 450–474 **Vulnerability Type**: Untrusted path handling in a destructive file operation **Risk Level**: High ### Vulnerable Code ```python USERPROFILE = os.environ.get("USERPROFILE", os.path.expanduser("~")) LOCALAPPDATA = os.environ.get("LOCALAPPDATA", os.path.join(USERPROFILE, "AppData", "Local")) APPDATA = os.environ.get("APPDATA", os.path.join(USERPROFILE, "AppData", "Roaming")) SYSTEMROOT = os.environ.get("SystemRoot", r"C:\Windows") ``` ```python def temp_roots(): roots = set() for v in [os.environ.get("TEMP"), os.environ.get("TMP"), os.path.join(SYSTEMROOT, "Temp"), os.path.join(LOCALAPPDATA, "Temp")]: if v and os.path.isdir(v) and not is_r3(v): roots.add(v) return roots def find_temp_targets(min_age_days): out = [] cutoff = time.time() - min_age_days * 86400 for root in temp_roots(): try: names = os.listdir(root) except OSError: continue for name in names: p = os.path.join(root, name) if is_r3(p): continue try: st = os.stat(p, follow_symlinks=False) except OSError: continue if st.st_mtime > cutoff: continue # Too new, skip if os.path.islink(p) or _is_junction_path(p): continue sz = walk_size(p) if os.path.isdir(p) else st.st_size out.append({"label": "System Temp", "path": p, "size": sz, "risk": "R1", "reason": f"Temporary file created over {min_age_days} days ago"}) return out ``` ```python def safe_remove(path, dry, fh): if is_r3(path): add_lesson(f"Blocked deletion: {path} matched an R3 zone", tag="automatic") return False ...[truncated 3458 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not treat environment variables as authoritative cleanup roots. Obtain standard Windows directories through trusted operating-system APIs, such as the appropriate Known Folder APIs. 2. Canonicalize every root and deletion target with `os.path.realpath()` and normalized case handling. 3. Maintain an immutable allowlist of canonical cleanup roots and require component-aware containment: ```python def is_within(path, root): path = os.path.realpath(path) root = os.path.realpath(root) return os.path.commonpath([path, root]) == root ``` 4. Immediately before deletion, require the target to be strictly beneath—not equal to—one approved root. 5. Reject relative paths, drive-relative paths, UNC paths, unexpected volumes, and roots whose ownership or access-control properties do not match expectations. 6. Revalidate links, junctions, and canonical containment immediately before the destructive operation to reduce path-substitution risks. 7. Display both the configured and canonical paths in the dry-run plan. 8. Add tests that substitute `TEMP`, `TMP`, `LOCALAPPDATA`, `APPDATA`, `USERPROFILE`, and `SystemRoot` with arbitrary directories and verify that cleanup is refused. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/disk_butler.py:450
Finding
Failed or Partial Deletions Are Recorded as Successful<![CDATA[ ## Vulnerability Details **File Location**: `scripts/disk_butler.py`, lines 450–474 and 690–698 **Vulnerability Type**: Incorrect error handling and cleanup audit-record corruption **Risk Level**: Medium ### Vulnerable Code ```python def safe_remove(path, dry, fh): if is_r3(path): add_lesson(f"Blocked deletion: {path} matched an R3 zone", tag="automatic") return False if os.path.islink(path) or _is_junction_path(path): add_lesson(f"Blocked deletion: {path} is a link or junction", tag="automatic") return False if dry: return True try: if os.path.isdir(path): shutil.rmtree(path, onerror=lambda f, p, e: None) else: os.remove(path) if fh: fh.write(json.dumps({"ts": now_iso(), "path": path, "ok": True}, ensure_ascii=False) + "\n") fh.flush() except Exception as e: if fh: fh.write(json.dumps({"ts": now_iso(), "path": path, "ok": False, "err": str(e)}, ensure_ascii=False) + "\n") fh.flush() return True ``` ```python n_ok = n_block = n_err = 0 with open(MANIFEST, "a", encoding="utf-8") as fh: fh.write(f"\n# clean {now_iso()} candidates={len(targets)}\n") for t in targets: ok = safe_remove(t["path"], dry=False, fh=fh) if ok is True: n_ok += 1 elif ok is False: n_block += 1 else: n_err += 1 ``` The English text in the first snippet translates messages for reporting clarity; the return and error-handling behavior is unchanged. ### Technical Analysis `safe_remove()` returns `True` at the end regardless of whether the deletion succeeded. If `os.remove()` or another operation raises an exception, the function writes an entry with `"ok": false` but then returns `True`. The caller therefore increments `n_ok` rather than `n_err`. Directory d ...[truncated 1957 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Return a distinct failure result from the exception handler: ```python except Exception as exc: write_failure(exc) return False ``` 2. Do not use an `onerror` callback that silently discards `shutil.rmtree()` failures. Collect and report every failed path or allow the exception to propagate. 3. Verify postconditions after deletion: ```python if os.path.lexists(path): record_failure("Target still exists after deletion") return False ``` 4. Use a structured result rather than a Boolean, for example: ```python RemoveResult(status="success" | "blocked" | "partial" | "failed", path=path, errors=[...]) ``` 5. Increment `n_ok` only after verified complete removal. Count blocked, partial, and failed operations separately. 6. Record partial directory deletion explicitly, including every child that could not be removed. 7. Make manifest writes resilient and internally consistent so the recorded status matches the function result. 8. Add automated tests for locked files, permission failures, disappearing targets, concurrently recreated files, and partially removable directory trees. ]]>
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (20)

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Tp2

High
Category
MCP Tool Poisoning
Confidence
85% confidence
Finding
Mixing characters from multiple Unicode scripts in a single identifier is a common technique to create visually ambiguous tool names.

Ae1

High
Category
analysis-evasion
Content
python scripts/disk_butler.py doctor
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/disk_butler.py doctor
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/disk_butler.py doctor
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/disk_butler.py doctor
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/disk_butler.py doctor
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/disk_butler.py doctor
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Ae1

High
Category
analysis-evasion
Content
python scripts/disk_butler.py doctor
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Intent-Code Divergence

High
Confidence
98% confidence
Finding
The documentation explicitly states '绝不整箱清空回收站' (never empty the recycle bin wholesale), yet the implementation later provides a command that does exactly that. This is dangerous because users and higher-level agents may rely on the stronger safety guarantee when deciding whether the skill is safe to run, creating a trust gap that can cause unexpected destructive behavior.

Description-Behavior Mismatch

High
Confidence
96% confidence
Finding
The skill advertises precise, safe recycle-bin handling and claims it will not touch user files, but it also exposes a `recycle --purge --yes` path that permanently deletes the entire recycle bin. Because recycle bins commonly contain user-deleted-but-not-yet-finalized personal files, this contradiction can lead to irreversible data loss if a user trusts the safety claims and invokes the command directly or via automation.

Natural-Language Policy Violations

Medium
Confidence
84% confidence
Finding
The README presents all user-facing instructions, warnings, and command explanations exclusively in Chinese. Under the stated policy, forcing a specific language without user opt-in can be a natural-language policy violation unless the locale restriction is clearly documented and justified.

Lp3

Medium
Category
MCP Least Privilege
Confidence
90% confidence
Finding
The skill advertises local file read/write capabilities and references executable scripts, but it does not declare any explicit tool scope such as permissions or allowed-tools. In an agent ecosystem, missing scope boundaries can lead to overbroad runtime authority, making destructive filesystem actions harder to constrain or audit.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The natural-language content throughout the skill file is presented in Chinese, including the name, description, commands context, and safety guidance, but there is no indication that users can choose another language or that the skill is intentionally restricted to a Chinese-speaking locale. Under the policy, forcing a specific language without opt-in is a language/locale policy concern.

Vague Triggers

Medium
Confidence
96% confidence
Finding
The trigger set includes broad phrases like '清理垃圾' and 'system cleanup', which can cause the skill to activate in ordinary conversation without clear user intent for filesystem modification. Because this skill is designed to inspect and potentially delete local data, accidental invocation increases the risk of unintended destructive workflows even if later confirmations exist.

Natural-Language Policy Violations

Medium
Confidence
93% confidence
Finding
The user-facing description, usage guidance, warnings, and output examples are written entirely in Chinese, which effectively imposes a single language/locale on users. The file does not indicate that other languages are supported or that Chinese is an opt-in or region-specific requirement.

Natural-Language Policy Violations

Medium
Confidence
90% confidence
Finding
The command output, warnings, confirmations, and argparse help strings are all presented in Chinese only. Because there is no mechanism for selecting language or any documented locale restriction, this is a natural-language policy concern under the language/locale rule.

Intent-Code Divergence

Medium
Confidence
82% confidence
Finding
The docstring says the free version does not include an executable auto mode and that this is only a capability entry/template. But the command then prints a concrete unattended sequence including `clean --yes --with-r2` and encourages handing it to an agent to run automatically, effectively enabling the very auto-clean workflow the docs say is excluded from free execution.

Static analysis

No suspicious patterns detected.