T02 · Agent Memory Poisoning
- Location
scripts/learner.py:64- Finding
Unvalidated Persistent Agent State Can Influence Future Sessions
- Content
View full analysis
Vulnerability Details
File Location:
scripts/learner.py:64-100; related behavioral instructions inSKILL.md:55-84andscripts/section.md:3-29
Vulnerability Type: Persistent agent memory poisoning
Risk Level: MediumComplete Code Snippet
python def load_learning(skill_dir): p = learn_path(skill_dir) try: return json.loads(open(p, encoding="utf-8").read()) except Exception: return default_data(os.path.basename(skill_dir)) def save_learning(skill_dir, data): data["lastUpdated"] = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M") p = learn_path(skill_dir) with open(p, "w", encoding="utf-8") as f: f.write(json.dumps(data, indent=2, ensure_ascii=False)) def record_op(skill_dir, capability, success=True, error=None, note=None): data = load_learning(skill_dir) data["totalOps"] += 1 cap = data["capabilityStats"].setdefault(capability, {"count": 0, "success": 0, "fail": 0}) cap["count"] += 1 if success: cap["success"] += 1 else: cap["fail"] += 1 data["totalErrors"] += 1 if error: ep = data["errorPatterns"].setdefault(error, {"count": 0, "lastNote": "", "lastTime": ""}) ep["count"] += 1 ep["lastNote"] = note or "" ep["lastTime"] = data["lastUpdated"] or datetime.datetime.now().strftime("%Y-%m-%dT%H:%M") rec = {"t": data["lastUpdated"], "cap": capability, "ok": success, "err": error, "note": note} data["recentOps"].append(rec) data["recentOps"] = data["recentOps"][-20:] save_learning(skill_dir, data) return data def record_preference(skill_dir, key, value): data = load_learning(skill_dir) data["preferences"][key] = value save_learning(skill_dir, data) return dataThe related skill instructions direct the agent to persist user preferences in
learned_patterns.json, apply them during lat ...[truncated 2837 chars]- Remediation
View remediation
Remediation Suggestions
-
Treat persisted values as untrusted data
- Explicitly instruct agents never to interpret stored notes, errors, capability names, or preference values as executable instructions.
- Render stored content in a clearly delimited data section when presenting it to an agent.
-
Introduce a strict preference schema
- Allow only predefined preference keys.
- Validate each value against an expected type and constrained set of values.
- Reject unknown fields, control characters, excessive lengths, and instruction-like multiline content.
-
Separate telemetry from behavioral configuration
- Store operational notes and error history separately from approved preferences.
- Do not place free-form notes into any context used to determine future agent behavior.
-
Require explicit review before applying state
- Present proposed preference changes to the user for confirmation.
- Record approval status and provenance for every preference.
- Ignore unapproved or externally modified entries.
-
Remove automatic instruction rewriting
- Do not direct the agent to copy learned content into
SKILL.md. - If skill improvement is required, generate a proposed patch and require trusted human review before applying it.
- Do not direct the agent to copy learned content into
-
Protect memory-file integrity
- Resolve and verify the canonical skill directory before writing.
- Reject symbolic links and unexpected file ownership.
- Use atomic file replacement with restrictive permissions.
- Optionally authenticate trusted state with a keyed integrity check.
-
Apply bounded input validation
- Limit lengths for capability names, errors, notes, keys, and values.
- Normalize Unicode and reject content containing role markers or instruction delimiters where they are not required.
-
