T01 · Skill Instruction Hijacking
Warning
- Location
- scripts/anatomy_scan.py:45
- Finding
- Untrusted Project Content Is Injected into Agent Session Context<![CDATA[ ## Vulnerability Details **File Location**: `scripts/anatomy_scan.py:45-99, 170-172`; `scripts/anatomy_inject.py:63-65`; `SKILL.md:61-69` **Vulnerability Type**: T01: Skill Instruction Hijacking **Risk Level**: Medium ### Vulnerable Code From `scripts/anatomy_scan.py:45-99`, descriptions are extracted directly from project-controlled file contents: ```python def extract_description(filepath: Path, max_chars: int = DEFAULT_DESC_CHARS) -> str: """Extract a one-line description from file content.""" try: with open(filepath, 'r', encoding='utf-8', errors='ignore') as f: lines = [] for i, line in enumerate(f): if i >= 30: # only scan first 30 lines break lines.append(line) except (OSError, UnicodeDecodeError): return '' text = ''.join(lines) desc = '' # Python docstring if filepath.suffix == '.py': for marker in ('"""', "'''"): idx = text.find(marker) if idx != -1: end = text.find(marker, idx + 3) if end != -1: desc = text[idx+3:end].strip().split('\n')[0] break # JS/TS first comment or export elif filepath.suffix in ('.js', '.ts', '.jsx', '.tsx', '.mjs'): for line in lines: stripped = line.strip() if stripped.startswith('//'): desc = stripped.lstrip('/ ').strip() break elif stripped.startswith('/**'): desc = stripped.lstrip('/* ').rstrip('* /').strip() break elif stripped.startswith('export'): desc = stripped[:max_chars] break # Markdown heading elif filepath.suffix in ('.md', '.mdx'): for line in lines: if line.startswith('#'): desc = line.lstrip('# ').strip() break # Shell script comment elif filepath. ...[truncated 3985 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Treat all extracted repository content as untrusted data and explicitly label the generated section accordingly, including a directive that descriptions must never be interpreted as instructions. 2. Prefer deterministic descriptions derived from file paths, extensions, syntax metadata, or locally defined templates rather than copying arbitrary prose from source files. 3. If content extraction remains necessary, detect and reject instruction-like phrases, tool requests, role declarations, and attempts to override previous instructions. Filtering should be defense in depth rather than the sole control. 4. Place extracted descriptions inside a strongly delimited data structure, such as JSON with explicit fields, and ensure the consuming Agent is instructed to parse those fields only as repository metadata. 5. Escape Markdown metacharacters, control characters, bidirectional Unicode controls, and formatting constructs before writing descriptions. This reduces presentation-layer manipulation, although it does not by itself prevent semantic prompt injection. 6. Separate index generation from automatic context injection. Require an explicit trust decision before adding an index generated from an unfamiliar repository to Agent context. 7. Update the startup instructions to state that `.anatomy.md` is attacker-controllable when generated from an untrusted project and must not override system, developer, user, or safety instructions. 8. Add security tests using malicious first-line comments, headings, and docstrings to verify that instruction-like content is rejected, neutralized, or clearly represented only as untrusted data. ]]>
