Back to skill

Security audit

Skill Sedimentation

Security checks for vulnerabilities and agentic risk

Overview

The skill openly implements agent self-learning, but it can automatically persist task content and modify memory or skill instructions with weak scoping and flawed safeguards.

Install only if you intentionally want an agent to keep persistent lessons from routine tasks and potentially alter future memory or skill behavior. Prefer explicit approval before writes, disable automatic post-task activation, and fix the path and write-limit checks before using it in a workspace with sensitive content.

Vulnerability Patterns
  • 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
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • 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 (4)

T02 · Agent Memory Poisoning

Error
Location
SKILL.md:22
Finding

Automatic Persistent Memory and Skill Modification

Content
View full analysis
Remediation
View remediation

T01 · Skill Instruction Hijacking

Error
Location
SKILL.md:283
Finding

Instruction Hierarchy and Self-Preservation Hijacking

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
SKILL.md:220
Finding

Filesystem Sandbox Escape Through String-Prefix Validation

Content
View full analysis
None: import pathlib, os if ".." in target_path: raise SecurityError(f"Illegal path sequence: {target_path}") real = pathlib.Path(target_path).resolve() allowed_parents = [ pathlib.Path("_core_files/memory").resolve(), pathlib.Path("_core_files/skills").resolve(), ] if not any(str(real).startswith(str(p)) for p in allowed_parents): raise SecurityError(f"Path traversal detected: {target_path}") if os.path.islink(target_path): link_target = os.path.realpath(target_path) if not any(link_target.startswith(str(p)) for p in allowed_parents): raise SecurityError(f"Symbolic-link traversal: {target_path}") ``` ### Technical Analysis The path check uses textual `startswith()` comparisons to determine whether a resolved path is beneath an allowed parent. String-prefix equality is not equivalent to filesystem ancestry. For example, if the approved directory is: ```text /project/_core_files/memory ``` then this sibling can pass the prefix test: ```text /project/_core_files/memory_evil/output.md ``` The symbolic-link destination check repeats the same vulnerable comparison. Checking only whether the final target is a symbolic link is also insufficient because an intermediate directory component may be a symbolic link. Resolving a path before checking it removes many simple traversal sequences, but it does not correct the prefix-boundary flaw. There is also a potential time-of-check/time-of-use risk if the validated path is later reopened by name. ### Attack Path 1. An attacker or attacker-influenced operation selects a destination whose absolute path begins with an allowed directory's string but is not its descendant. 2. For example, a ...[truncated 919 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
SKILL.md:241
Finding

Global Write-Amplitude Limit Bypassed for New Files

Content
View full analysis
tuple: """ Returns (allowed: bool, split_count: int, reason: str). If the write exceeds 5%, split it into batches separated by at least one conversation turn. If the destination does not exist, allow it as a new file. """ import os if not os.path.exists(target_file_path): return (True, 1, "New file; no amplitude restriction") current_size = os.path.getsize(target_file_path) ratio = new_content_size / max(current_size, 1) if ratio <= 0.05: return (True, 1, f"Amplitude {ratio:.2%} <= 5%; write directly") split_count = max(2, int(ratio / 0.05) + 1) return (True, split_count, f"Amplitude {ratio:.2%} > 5%; split into {split_count} writes") ``` ### Technical Analysis The function claims to enforce a global 5% write-amplitude restriction but explicitly exempts nonexistent files. Consequently, an initial write can contain substantially more data than would be permitted when updating an existing file. The function also always returns `allowed=True`, including when the ratio exceeds 5%. It relies on callers to honor `split_count`, but no enforcement mechanism is shown in the audited project. A caller that ignores the advisory batch count can perform the entire write immediately. Although `sedimentation_guard()` documents a separate one-megabyte content limit, the document does not demonstrate that this guard is inseparably enforced by the actual write primitive. The new-file exemption is especially relevant because Promote is expressly allowed to create new Skill files. ### Attack Path 1. Attacker-influenced content is selected for pro ...[truncated 1009 chars]
Remediation
View remediation
Vulnerability Patterns
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • 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
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
Findings (3)

Vague Triggers

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill is designed to auto-activate after many ordinary task completions and explicitly says it does not require a user request. Because it persists task-derived data and may modify memory or skill files, broad automatic triggering increases the chance of unreviewed retention of sensitive data and unintended self-modification from routine interactions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill describes multiple persistent write paths, including reflections, promotions, MEMORY/TABOOS, and even updates to other skill documents, but does not clearly warn users up front that task-derived content may be stored or propagated. This undermines informed consent and raises privacy and integrity risks, especially because the skill can run automatically after task completion.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
95% confidence
Finding

The class is documented as an in-memory file system adapter using path -> content_bytes, which indicates it should preserve file contents for realistic file-system-like behavior. However, write() saves len(data) instead of the bytes themselves, so subsequent read() returns an integer-like size value rather than the original content, contradicting the stated intent of the adapter.

Content

No source excerpt is available for this finding.