T02 · Agent Memory Poisoning
Error
- Location
- SKILL.md:22
- Finding
- Persistent Skill Poisoning Through Untrusted Memory Content## Vulnerability Details **File Location**: `SKILL.md`, lines 22-69 **Vulnerability Type**: Persistent injection of untrusted content into generated agent skills **Risk Level**: High ### Vulnerable Code ```powershell $memoryFiles = Get-ChildItem "memory/" -Filter "*.md" | Sort-Object LastWriteTime -Descending | Select-Object -First 7 $patterns = @{} foreach ($file in $memoryFiles) { $content = Get-Content $file.FullName -Raw if ($content -match "Failed|Blocker|Error") { # Extract pattern $matches = [regex]::Matches($content, "(Failed|Blocker|Error): (.+)") foreach ($m in $matches) { $key = $m.Groups[2].Value $patterns[$key] = $patterns[$key] + 1 } } } # Find repeated patterns (2+ occurrences) $repeated = $patterns.GetEnumerator() | Where-Object { $_.Value -ge 2 } ``` ```powershell foreach ($pattern in $repeated) { $skillName = $pattern.Key -replace '[^a-z]', '-' -replace '-+', '-' $skillPath = "skills/local/$skillName-recovery" New-Item -ItemType Directory -Path $skillPath -Force | Out-Null $skillContent = @" --- name: $skillName-recovery description: Auto-recovery for: $($pattern.Key) --- # $($pattern.Key) Recovery ## Trigger When $($pattern.Key) occurs ## Steps 1. Detect the error pattern 2. Execute recovery steps 3. Verify resolution ## Verification - [ ] Error resolved - [ ] Task can continue "@ $skillContent | Out-File "$skillPath/SKILL.md" -Encoding UTF8 } ``` ### Technical Analysis The complete value following an `Error:`, `Failed:`, or `Blocker:` prefix is treated as a trusted pattern. It is interpolated directly into the metadata, title, and trigger text of a persistent `SKILL.md` file. There is no validation of the content's origin, semantic meaning, Markdown structure, or suitability as an agent instruction. Although filename characters a ...[truncated 1705 chars]
- Remediation
- ## Remediation Suggestions - Treat all memory-file content as untrusted input. - Parse only a strict, structured error identifier rather than arbitrary text following an error prefix. - Enforce length limits and an allowlist of permitted characters and error identifiers. - Reject line breaks, YAML delimiters, Markdown headings, code fences, links, tool directives, and instruction-like phrases. - Serialize generated metadata using a YAML library rather than string interpolation. - Escape content before placing it in Markdown and keep data separate from executable agent instructions. - Require explicit human review and approval before generated skills are written, registered, or loaded. - Store generated drafts in a non-discoverable quarantine directory until approved. - Record the source files and hashes used to generate each skill to support provenance checks. - Prevent generated skills from granting themselves tools, permissions, or automatic activation behavior.
