T02 · Agent Memory Poisoning
Error
- Location
- scripts/record_feedback.py:48
- Finding
- Persistent Agent Instruction Poisoning Through Unsanitized Feedback<![CDATA[ ## Vulnerability Details **File Location**: `scripts/record_feedback.py:48-74` **Supporting Locations**: `SKILL.md:28-34`, `SKILL.md:119-126`, `references/workflow.md:306-315` **Vulnerability Type**: Persistent instruction injection through user-controlled feedback **Risk Level**: High ### Vulnerable Code ```python def main() -> int: parser = argparse.ArgumentParser(description="Record user subtitle feedback and optionally update reusable gates.") parser.add_argument("--issue", required=True) parser.add_argument("--category", required=True) parser.add_argument("--fix", required=True) parser.add_argument("--video", default="") parser.add_argument("--timestamp", default="") parser.add_argument("--cause", default="") parser.add_argument("--reusable", choices=["yes", "no"], default="yes") args = parser.parse_args() entry = f""" ### {date.today().isoformat()} - {args.category} - {args.issue} Date: {date.today().isoformat()} Video/output: {args.video or "not specified"} Timestamp: {args.timestamp or "not specified"} Category: {args.category} User issue: {args.issue} Confirmed cause: {args.cause or "to be confirmed during review"} Fix applied: {args.fix} Reusable: {args.reusable} SOP update: {"required" if args.reusable == "yes" else "not required"} Quality gate update: {"required" if args.reusable == "yes" else "not required"} """ append_under_heading(LEDGER, "## Entries", entry) print(f"Recorded feedback in {LEDGER}") if args.reusable == "yes": marker = f"Feedback gate: {args.category} - {args.issue}" gate = f"| <!-- {marker} --> {args.category}: {args.issue} | Same or similar user-visible subtitle problem appears during review | {args.fix} |" workflow = f""" <!-- Feedback workflow: {args.category} - {args.issue} --> ## Feedback Prevention: {args.category} When this pattern appears: {args.issue} Prevent it by: {args.fix} """ gate_changed = insert_before_heading_onc ...[truncated 4004 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions 1. **Do not write raw feedback into instruction files** - Store feedback in a structured data file such as JSON. - Keep user observations distinct from trusted workflow rules. - Treat ledger entries as untrusted data that must never be followed as instructions. 2. **Require trusted approval for workflow changes** - Generate proposed changes in a separate review file. - Require explicit human approval before modifying `workflow.md`, `quality-gates.md`, or `SKILL.md`. - Do not automatically repackage a Skill containing unreviewed feedback. 3. **Validate every feedback field** - Replace free-form categories with a fixed allowlist. - Set conservative maximum lengths. - Reject newline characters, control characters, null bytes, and bidirectional text controls where single-line values are expected. - Validate timestamps and other structured fields with strict parsers. 4. **Escape presentation syntax** - Escape Markdown table separators, headings, HTML comment delimiters, backticks, and other formatting tokens before writing display-only records. - Do not rely on escaping alone for instruction files; approval and data/instruction separation remain necessary. 5. **Change the persistence default** - Default `--reusable` to `no`. - Require an explicit reviewed option to propose a reusable rule. - Ensure a reusable rule contains trusted, normalized text rather than the original user submission. 6. **Add defensive guidance** - State explicitly that text in feedback ledgers and generated proposals is untrusted. - Instruct the Agent not to execute or follow directives embedded in issue descriptions, subtitle text, metadata, or proposed fixes. 7. **Add security tests** - Test multiline values, Markdown headings, HTML comments, code fences, table separators, and instruction-like phrases. - Verify that malicious test inputs cannot alter trusted workflow semantics or become automatica ...[truncated 28 chars]
