Back to skill

Security audit

Context Engineering For Projects

Security checks for vulnerabilities and agentic risk

Overview

This skill has a coherent documentation purpose, but its scaffold script can create persistent files outside the intended project folder if given an unsafe project name.

Install only if you are comfortable with the skill reading a chosen code directory and creating persistent context files. Use simple project names containing only letters, digits, dots, underscores, or hyphens, and avoid using untrusted text as the project name until the script validates path containment and escapes Markdown.

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/init_context_project.py:99
Finding
Unvalidated Project Name Enables Path Traversal and Arbitrary File Creation<![CDATA[ ## Vulnerability Details **File Location**: `scripts/init_context_project.py`, lines 99-149 **Vulnerability Type**: Path traversal and insufficient input validation **Risk Level**: High ### Vulnerable Code ```python def main(): parser = argparse.ArgumentParser(description="Initialize a team-style project context directory.") parser.add_argument("--project", required=True, help="Project name (folder name).") parser.add_argument("--code-dir", required=True, help="Absolute path to the code directory.") parser.add_argument( "--target-root", default=str(Path.home() / "clawDir" / "team"), help="Target root for team context (default: ~/clawDir/team).", ) args = parser.parse_args() target_root = Path(args.target_root).expanduser().resolve() code_dir = Path(args.code_dir).expanduser().resolve() project_root = target_root / "projects" / args.project date = datetime.now().strftime("%Y-%m-%d") created = [] created.append(write_if_missing(target_root / "readme.md", "# Team Directory Guide\n\n- Keep navigation here.\n")) append_project_index(target_root / "projects" / "projects.md", args.project) write_if_missing(project_root / "readme.md", TEMPLATE_README.format(project=args.project, code_dir=code_dir, project_root=project_root)) write_if_missing(project_root / "goals.md", TEMPLATE_GOALS) write_if_missing(project_root / "skill.md", TEMPLATE_SKILL) write_if_missing(project_root / "project_status.md", TEMPLATE_STATUS.format(date=date)) write_if_missing(project_root / "decisions.md", TEMPLATE_DECISIONS.format(date=date)) write_if_missing(project_root / "agents" / "agents.md", TEMPLATE_AGENTS) write_if_missing(project_root / "modules" / "README.md", TEMPLATE_MODULES_README) write_if_missing(project_root / "references" / "entrypoints.md", "# Entrypoints\n\n- TODO: record key entrypoints and indices.\n") modules = infer_modules(code_dir) for module i ...[truncated 3106 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Restrict `--project` to a single safe filesystem identifier: ```python import re PROJECT_NAME_PATTERN = re.compile(r"^[A-Za-z0-9][A-Za-z0-9._-]*$") if not PROJECT_NAME_PATTERN.fullmatch(args.project): parser.error( "--project must contain only letters, digits, periods, underscores, " "or hyphens and must begin with a letter or digit" ) ``` 2. Explicitly reject dangerous path forms: - Absolute paths. - `/` and `\` path separators. - Empty names. - `.` and `..`. - Names containing control characters. 3. Resolve and verify destination containment before creating files: ```python projects_root = (target_root / "projects").resolve() project_root = (projects_root / args.project).resolve() if not project_root.is_relative_to(projects_root): parser.error("--project resolves outside the projects directory") ``` 4. Perform the containment check immediately before file creation to reduce the risk of path changes or unsafe refactoring. 5. Where the environment may be controlled by an attacker, consider defenses against symbolic-link traversal, such as rejecting symlinked destination components or using directory-relative, no-follow file operations. 6. Add automated tests for: - `../outside` - `../../outside` - Absolute Unix and Windows paths - Embedded forward and backward slashes - `.` and `..` - Valid names containing permitted punctuation ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/init_context_project.py:26
Finding
Project Name Allows Persistent Markdown and Agent-Context Injection<![CDATA[ ## Vulnerability Details **File Location**: `scripts/init_context_project.py`, lines 26-39 **Vulnerability Type**: Persistent Markdown injection and context poisoning **Risk Level**: Medium ### Vulnerable Code ```python def append_project_index(projects_index: Path, project_name: str): ensure_parent(projects_index) if not projects_index.exists(): projects_index.write_text( "# Projects\n\n- All project contexts live under this folder.\n\n## Index\n", encoding="utf-8", ) text = projects_index.read_text(encoding="utf-8") entry = f"- {project_name} → projects/{project_name}/readme.md" if entry in text: return False new_text = text.rstrip() + "\n" + entry + "\n" projects_index.write_text(new_text, encoding="utf-8") return True ``` ### Technical Analysis The attacker-controlled `project_name` is interpolated twice into a persistent Markdown document without validation or escaping: ```python entry = f"- {project_name} → projects/{project_name}/readme.md" ``` A project name can contain newline characters, Markdown headings, links, comments, or instruction-like text. These values are written to `projects/projects.md`, which serves as a navigation index for project contexts. Because this project is designed for agent context engineering, generated Markdown may later be loaded and interpreted by an AI agent. Injected content can therefore appear as trusted project guidance rather than as an untrusted project identifier. This creates a context-poisoning risk, although the audited package does not itself contain an active malicious instruction. The same unvalidated value is also embedded in the generated project README through `TEMPLATE_README.format(project=args.project, ...)`, extending the persistence of injected Markdown. ### Attack Path 1. An attacker supplies a project name containing newline-delimited Markdown: ```bash python scripts/init_context_project.py \ ...[truncated 1286 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Apply a strict project identifier allowlist before using the value in either paths or documents: ```python if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9._-]*", args.project): parser.error("Invalid project name") ``` 2. Reject all line breaks and control characters even if a broader naming policy is adopted: ```python if any(ord(ch) < 32 or ord(ch) == 127 for ch in args.project): parser.error("Project name cannot contain control characters") ``` 3. Separate filesystem identifiers from human-readable display names. The identifier should remain strictly constrained, while any display name should be escaped before insertion into Markdown. 4. If arbitrary display text must be supported, escape Markdown metacharacters and normalize it to one line before persistence. 5. Do not treat generated documents containing user-supplied content as trusted agent instructions. Mark user-derived fields explicitly and keep them separate from executable or authoritative instruction sections. 6. Add tests confirming that names containing newlines, headings, links, HTML comments, and instruction-like text are rejected and cannot alter the structure of `projects.md`. ]]>
Vulnerability Patterns
  • Rogue AgentSelf-Modification, Session Persistence
  • Trigger AbuseOverly Broad Trigger, Shadow Command Trigger, Keyword Baiting Trigger
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
Findings (3)

Self-Modification

High
Category
Rogue Agent
Content
--target-root <target_root>
     ```
   - The script infers module buckets from the codebase and creates module folders dynamically.
   - The script is idempotent: it won’t overwrite existing files.

4. **Populate content (critical)**
   - Fill `skill.md` (L1) with **project summary, architecture, entrypoints, build/run, module navigation**.
Confidence
88% confidence
Finding
The skill directs the agent to populate and modify project files, including SKILL.md and multiple generated documents, based on analysis of a user-specified codebase and target root. Even if the bundled script is described as idempotent, the workflow still authorizes broad repository and workspace modification, which can alter prompts/configuration-like files and create persistence in locations the user may not expect.

Lp3

Medium
Category
MCP Least Privilege
Confidence
92% confidence
Finding
The skill clearly instructs reading from a user-supplied code directory and writing a scaffold under a target root, but it declares no explicit tool scope or allowed-tools boundary. That creates an authorization ambiguity where an agent may perform file read/write actions more broadly than intended, increasing the chance of unintended filesystem access or writes.

Vague Triggers

Medium
Confidence
90% confidence
Finding
The activation text includes broad English phrases like 'create project context' and 'set up team context' that can overlap with many normal documentation or project-setup requests. Over-broad triggering can invoke this skill unexpectedly, causing unsolicited codebase scanning and filesystem writes in contexts where the user did not specifically intend this operation.

Static analysis

No suspicious patterns detected.