T02 · Agent Memory Poisoning
Error
- Location
- scripts/forge.py:535
- Finding
- Untrusted Repair Reports Can Poison Cross-Project Agent Memory<![CDATA[ ## Vulnerability Details **File Location**: `scripts/forge.py:535-560` **Vulnerability Type**: Persistent cross-project prompt and memory poisoning **Risk Level**: High ### Vulnerable Code ```python # Save repair pattern to reflections (two-layer) pattern = report.get("repair_pattern", {}) if pattern and pattern.get("pattern_name"): # Project layer: full detail (file names, paths, project-specific context) project_reflections = Path(state["workdir"]) / "forge-reflections.jsonl" with open(project_reflections, "a") as f: f.write(json.dumps(pattern, ensure_ascii=False) + "\n") # Universal layer: extract abstract pattern (no project-specific paths/filenames) universal_pattern = extract_universal_pattern(pattern) if universal_pattern: universal_dir = FORGE_DIR / "reflections" universal_dir.mkdir(parents=True, exist_ok=True) universal_file = universal_dir / "patterns.jsonl" # Dedup: skip if pattern_name already exists existing_names = set() if universal_file.exists(): try: for line in universal_file.read_text().strip().split("\n"): if line.strip(): existing_names.add(json.loads(line).get("pattern_name", "")) except Exception: pass if universal_pattern["pattern_name"] not in existing_names: with open(universal_file, "a") as f: f.write(json.dumps(universal_pattern, ensure_ascii=False) + "\n") ``` The persistent records are subsequently read at `scripts/forge.py:256-284`, and fields such as `pattern_name` and `solution_template` are inserted into prompts generated for future repair agents. ### Technical Analysis Forge treats the repair report as trusted even though it is generated by an LLM operating on potentially attacker-controlled project fi ...[truncated 2599 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Disable cross-project promotion of model-generated reflections by default. 2. Keep reflections isolated per project or per explicitly defined trust domain. 3. Require explicit human approval before adding any record to universal storage. 4. Replace free-form reflection fields with a strict schema containing short, declarative, allowlisted values. 5. Reject content containing prompt delimiters, role declarations, tool instructions, shell commands, paths, URLs, or imperative agent directives. 6. Treat all reflection text as untrusted data in generated prompts. Clearly delimit and label it as non-authoritative reference material that must never override system, user, or safety instructions. 7. Store provenance metadata, including the source project, task, report hash, creation time, and approval identity. 8. Apply length limits and canonicalization before validation and persistence. 9. Protect the universal reflection file from writes by ordinary repair workflows. 10. Review and purge existing universal patterns before deploying the corrected implementation. ]]>
