T02 · Agent Memory Poisoning
Warning
- Location
- lib/cost-tracker.js:87
- Finding
- Persistent Agent-Readable Log Injection Through Unsanitized Metadata<![CDATA[ ## Vulnerability Details **File Location**: `lib/cost-tracker.js:87-109`; related agent-reading behavior is documented in `README.md:48-54` **Vulnerability Type**: Persistent Markdown and instruction injection **Risk Level**: Medium ### Vulnerable Code ```javascript function logSpawn(label, model, estimatedCost, approved, options = {}) { initializeCostTracking(); const timestamp = new Date().toISOString().replace('T', ' ').substring(0, 16); const approvedStr = approved === 'auto' ? 'auto' : (approved ? 'yes' : 'no'); const entry = `### [${timestamp}] ${label} - **Model:** ${model} - **Task Type:** ${options.taskType || 'unknown'} - **Estimated:** $${estimatedCost.toFixed(2)} - **Actual:** $0.00 (pending) - **Approved:** ${approvedStr} ${options.notes ? `- **Notes:** ${options.notes}\n` : ''} --- `; fs.appendFileSync(COST_TRACKING_FILE, entry); } ``` The project documentation states that the agent reads the tracking file during cost checks: ```markdown Agent reads this file on each cost check. ``` ### Technical Analysis The `label`, `model`, `options.taskType`, and `options.notes` values are interpolated directly into an agent-readable Markdown file without validation, length restrictions, newline removal, or Markdown escaping. If any of these fields can be influenced by an untrusted user or subagent request, a value containing newline characters can escape its intended field and add arbitrary headings, fake cost records, or instruction-like text. Because the resulting content is persisted in `notes/cost-tracking.md` and the documentation directs agents to read that file during later checks, the injection can affect sessions beyond the request that created it. This is a persistent content-injection weakness. Whether injected text is ultimately obeyed depends on how the surrounding agent treats workspace notes, but the code does not establish a data/instruction boundary. ### Attack Path 1. An attacker supplies or influences ...[truncated 1336 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. Treat every metadata field as untrusted data. 2. Enforce bounded, single-line values for `label`, `model`, and `taskType`: - Remove carriage returns and line feeds. - Reject control characters. - Apply strict maximum lengths. - Restrict `model` and `taskType` to explicit allowlists. 3. Escape Markdown metacharacters before writing free-form values. 4. Restrict notes to a bounded length and encode line breaks rather than preserving raw Markdown. 5. Store authoritative records in a structured format such as JSON with schema validation. Generate Markdown summaries only as escaped presentation output. 6. Tell agents that tracking-file content is untrusted data and must never be interpreted as instructions. 7. Where possible, avoid loading arbitrary labels and notes into agent instruction context. 8. Add tests covering labels and notes containing newlines, headings, separators, code fences, and instruction-like content. ]]>
