T02 · Agent Memory Poisoning
- Location
- utils/config_manager.py:128
- Finding
- Persistent Agent Memory Injection Through Unsanitized TTS Configuration## Vulnerability Details **File Location**: `utils/config_manager.py:128-153`; related input handling in `scripts/configure_tts.py:147-162` **Vulnerability Type**: Persistent agent memory poisoning **Risk Level**: High ### Vulnerable Code ```python def save_tts_config(self, config: TTSConfig): """ Save TTS configuration. Args: config: TTS configuration """ content = self._read_memory() tts_section = f""" ## TTS Configuration - Provider: {config.provider} - Model: {config.model} - Voice: {config.voice} - Emotion: {config.emotion} - Speed: {config.speed} - Pitch: {config.pitch} """ if "## TTS Configuration" in content: content = re.sub( r'## TTS Configuration.*?(?=\n##|\Z)', tts_section.strip(), content, flags=re.DOTALL ) else: content += "\n" + tts_section self._write_memory(content) ``` The relevant command-line inputs are accepted without validation: ```python parser.add_argument('--voice', type=str, help='Voice ID') parser.add_argument('--emotion', type=str, help='Emotion type') parser.add_argument('--speed', type=float, help='Speech speed') parser.add_argument('--pitch', type=float, help='Pitch') parser.add_argument('--model', type=str, help='Model name') args = parser.parse_args() if args.test: asyncio.run(test_tts()) else: asyncio.run(configure_tts( voice=args.voice, emotion=args.emotion, speed=args.speed, pitch=args.pitch, model=args.model )) ``` ### Technical Analysis String-valued configuration fields such as `model`, `voice`, and `emotion` are directly interpolated into Markdown and written to `~/.openclaw/MEMORY.md`. There is no rejection or encoding of carriage returns, line feeds, Markdown headings, or instruction-like text. A malicious value can therefore terminate ...[truncated 1736 chars]
- Remediation
- ## Remediation Suggestions 1. Store Skill configuration in a dedicated structured file, such as a Skill-scoped JSON or SQLite record, rather than in agent instruction memory. 2. Define strict allowlists for `provider`, `model`, `voice`, and `emotion`. Reject unknown values instead of accepting arbitrary strings. 3. Reject carriage returns, line feeds, null bytes, Markdown headings, and other formatting control characters in every value written to memory. 4. If Markdown storage is unavoidable, serialize values using a format that cannot create new Markdown structure and decode them only within trusted code. 5. Separate persistent user preferences from instruction-bearing memory so configuration data cannot be interpreted as agent directives. 6. Validate values again at the persistence boundary, even if callers also perform validation. 7. Add tests using multiline values and Markdown headings to verify that they cannot alter the structure of `MEMORY.md`.
