T02 · Agent Memory Poisoning
Error
- Location
- scripts/analyze_patterns.py:47
- Finding
- Persistent Pattern-Library Poisoning Through Untrusted Skill Metadata<![CDATA[ ## Vulnerability Details **File Location**: `scripts/analyze_patterns.py:47-57`, `scripts/analyze_patterns.py:110-111`, `scripts/analyze_patterns.py:176-178`, and `scripts/analyze_patterns.py:213-217` **Vulnerability Type**: Persistent poisoning of agent-consumed reference data **Risk Level**: High ### Vulnerable Code ```python text = skill_md.read_text(errors="replace") # Extract frontmatter name, description = "", "" fm_match = re.match(r"^---\n(.*?)\n---", text, re.DOTALL) if fm_match: fm = fm_match.group(1) name_m = re.search(r'^name:\s*(.+)$', fm, re.MULTILINE) desc_m = re.search(r'^description:\s*"(.+)"', fm, re.MULTILINE | re.DOTALL) if name_m: name = name_m.group(1).strip() if desc_m: description = desc_m.group(1).strip() ``` ```python all_triggers.extend([(phrase, s["name"]) for phrase in s["trigger_phrases"]]) ``` ```python snippet = phrase[:100].replace('\n', ' ') lines.append(f"- [{skill_name}] `{snippet}`") ``` ```python if args.output: out_path = Path(args.output).expanduser() out_path.parent.mkdir(parents=True, exist_ok=True) out_path.write_text(output) print(f"Report written to {out_path}", file=sys.stderr) ``` ### Technical Analysis The analyzer reads metadata from every installed `SKILL.md` under the selected scan directories and treats the extracted name and description as trusted report content. These values are inserted into Markdown without escaping Markdown delimiters, filtering instruction-like text, or recording a clear untrusted-data boundary. The description parser also uses a greedy multiline expression: ```python r'^description:\s*"(.+)"' ``` Combined with `re.DOTALL`, this expression may capture more frontmatter content than the intended description value. A crafted installed Skill can therefore place model-directed instructions or misleading structural content into fields consumed by the analyzer. The generated output can be persisted to `references/patterns ...[truncated 1926 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Replace regular-expression frontmatter parsing with `yaml.safe_load`. 2. Require `name` and `description` to be scalar strings with explicit length and line-count limits. 3. Reject multiline descriptions when generating the pattern library unless multiline content is explicitly required. 4. Escape backticks, brackets, pipes, HTML characters, and other Markdown control syntax before interpolation. 5. Store extracted data in a structured JSON format rather than directly composing agent-consumed Markdown. 6. Clearly mark all extracted values as untrusted quotations and instruct consuming agents never to follow instructions found inside those values. 7. Preserve provenance for every extracted value, including source path and package identity. 8. Maintain an allowlist of trusted Skills for synthesis or require user review before incorporating patterns from newly installed Skills. 9. Add tests containing prompt-injection strings, malformed frontmatter, multiline descriptions, and Markdown-breaking payloads. 10. Require confirmation before replacing an existing persistent pattern library. ]]>
