Back to skill

Security audit

Workspace Hygiene Publish

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly does what it says, but its filesystem handling can let a crafted workspace cause reads or writes outside the selected workspace.

Review before installing. Use it only on workspaces you trust, avoid running it automatically on untrusted or shared workspaces, and do not use --fix until symlink containment, backup, and clearer dry-run behavior are added. There is no evidence here of hidden networking or intentional exfiltration, but the filesystem escape risk is material.

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/hygiene.py:191
Finding
Workspace Symlink Traversal Allows Reads and Writes Outside the Audited Workspace## Vulnerability Details **File Location**: `scripts/hygiene.py`, lines 191-211 and 440-450 **Vulnerability Type**: Unrestricted symlink following and insufficient filesystem boundary validation **Risk Level**: High ### Vulnerable Code ```python def append_memory_content(target_path: Path, source_path: Path) -> bool: source_text = load_text(source_path) if not source_text.strip(): return False target_text = load_text(target_path) if source_text.strip() in target_text: return False if target_text and not target_text.endswith("\n"): target_text += "\n" if target_text.strip(): merged = target_text.rstrip() + "\n\n" + source_text.strip() + "\n" else: merged = source_text.rstrip() + "\n" target_path.parent.mkdir(parents=True, exist_ok=True) target_path.write_text(merged, encoding="utf-8") return True ``` ```python def write_report(result: AuditResult, report_date: dt.date, report_only: bool) -> Path: report_dir = result.workspace / "projects" / "system" if not report_dir.exists() and not report_only: report_dir.mkdir(parents=True, exist_ok=True) result.fixes.append("Created report directory: projects/system") elif not report_dir.exists(): report_dir.mkdir(parents=True, exist_ok=True) report_path = report_dir / "hygiene-{0}.md".format(report_date.isoformat()) report_path.write_text(render_report(result, report_date), encoding="utf-8") result.report_path = report_path return report_path ``` ### Technical Analysis The skill treats the audited workspace as trusted and performs filesystem reads and writes without verifying whether path components or files are symbolic links. Python operations including `Path.exists()`, `Path.is_file()`, `Path.read_text()`, and `Path.write_text()` ordinarily follow symlinks. Two exploitable paths result: 1. `write_report ...[truncated 2968 chars]
Remediation
## Remediation Suggestions 1. Treat every audited workspace and all of its contents as untrusted input. 2. Resolve each source, destination, and parent directory before access, then verify containment beneath the resolved workspace root: ```python workspace_root = result.workspace.resolve(strict=True) candidate = target_path.resolve(strict=False) candidate.relative_to(workspace_root) ``` Reject the operation if `relative_to()` raises `ValueError`. 3. Explicitly reject symlinks for memory source files, daily target files, `projects`, `projects/system`, and report files. Check every existing path component rather than only the final path. 4. For write operations, use descriptor-based APIs with no-follow semantics such as `os.open()` with `O_NOFOLLOW` where supported. Use safe create or replace behavior to reduce time-of-check/time-of-use races. 5. Open and validate trusted parent-directory descriptors, then perform relative operations through those descriptors where platform support permits. 6. Do not overwrite an existing report without an explicit option. Consider exclusive file creation or a securely generated filename. 7. Before `--fix` reads a memory file, require that it is a regular, non-symlinked file located directly inside the validated `memory` directory. 8. Before writing a daily memory file, reject an existing symlink or non-regular file and verify that the resolved parent remains inside the workspace. 9. Make `--report-only` genuinely non-mutating, or rename and document the option to clarify that it still writes a report. 10. Add regression tests using symlinked source files, target files, and parent directories to confirm that all attempted workspace escapes are rejected.
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 (5)

Lp3

Medium
Category
MCP Least Privilege
Confidence
91% confidence
Finding
The skill explicitly describes reading workspace files, scanning memory and project folders, and writing a hygiene report, yet it declares no tool or permission scope. That mismatch makes the skill harder to sandbox or review and can allow broader file access/modification than users or the platform may expect.

Vague Triggers

Medium
Confidence
93% confidence
Finding
The trigger phrases are broad and generic to normal workspace assistance, which increases the chance the skill is invoked in situations where the user only wanted advice rather than an auditing/modifying workflow. Because the skill can scan and potentially alter files, overbroad activation raises the risk of unintended execution on sensitive or unrelated workspaces.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill documents auto-consolidating memory files and writing reports, but it does not prominently warn that it will modify workspace files. Users may reasonably interpret a hygiene audit as read-only, so silent or insufficiently disclosed writes can lead to unexpected data changes, loss of provenance, or accidental alteration of important memory records.

Intent-Code Divergence

Medium
Confidence
98% confidence
Finding
The help text promises 'Audit and report without applying fixes' and implies no workspace modification, but the program still creates directories and writes a report. This documentation/behavior mismatch is dangerous because operators and higher-level agents may select report-only mode expecting safe inspection, yet the tool still performs state-changing actions.

Description-Behavior Mismatch

Medium
Confidence
97% confidence
Finding
The implementation writes a report file even when --report-only is set, so a mode advertised as non-modifying still changes the workspace. In an automation or auditing context, this can violate read-only expectations, alter evidence, trigger downstream workflows, or fail in environments where the workspace must not be mutated.

Static analysis

No suspicious patterns detected.