T02 · Agent Memory Poisoning
- Location
utils/config_manager.py:128- Finding
Persistent Agent Memory Injection Through Unsanitized TTS Configuration
- Content
View full analysis
Vulnerability Details
File Location:
utils/config_manager.py:128-153; related input handling inscripts/configure_tts.py:147-162
Vulnerability Type: Persistent agent memory poisoning
Risk Level: HighVulnerable 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, andemotionare 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
View remediation
Remediation Suggestions
- Store Skill configuration in a dedicated structured file, such as a Skill-scoped JSON or SQLite record, rather than in agent instruction memory.
- Define strict allowlists for
provider,model,voice, andemotion. Reject unknown values instead of accepting arbitrary strings. - Reject carriage returns, line feeds, null bytes, Markdown headings, and other formatting control characters in every value written to memory.
- If Markdown storage is unavoidable, serialize values using a format that cannot create new Markdown structure and decode them only within trusted code.
- Separate persistent user preferences from instruction-bearing memory so configuration data cannot be interpreted as agent directives.
- Validate values again at the persistence boundary, even if callers also perform validation.
- Add tests using multiline values and Markdown headings to verify that they cannot alter the structure of
MEMORY.md.
