T02 · Agent Memory Poisoning
Warning
- Location
- scripts/log_rejection.sh:4
- Finding
- Persistent Agent Memory Poisoning Through Unescaped Markdown Log Entries<![CDATA[ ## Vulnerability Details **File Location**: `scripts/log_rejection.sh:4-19` **Vulnerability Type**: Persistent untrusted-content injection **Risk Level**: Medium ### Vulnerable Code ```bash TARGET=$1 REASON=$2 ALT=$3 TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") ID="REJ-$(date +%Y%m%d)-$((RANDOM%900+100))" LEARNINGS_DIR=".learnings" FILE="$LEARNINGS_DIR/REJECTIONS.md" mkdir -p "$LEARNINGS_DIR" if [ ! -f "$FILE" ]; then echo "# Rejection Logs" > "$FILE" fi echo -e "\n## [$ID] $TARGET\n\n**Timestamp**: $TIMESTAMP\n**Decision**: REJECTED\n**Reason**: $REASON\n**Alternative**: $ALT" >> "$FILE" echo "✅ Logged rejection: $ID" ``` ### Technical Analysis The script accepts three caller-controlled arguments and directly appends them to `.learnings/REJECTIONS.md` without validation, encoding, or Markdown escaping. The use of `echo -e` is particularly unsafe because backslash escape sequences in the supplied values may be interpreted. An attacker can therefore inject line breaks, fabricated log entries, Markdown headings, or instruction-like content. The destination is explicitly presented as a learning and audit file. If this file is later loaded into an agent's context or treated as trusted long-term state, injected content may influence future sessions. The vulnerability does not directly execute shell commands because the variables are expanded inside a quoted argument, but it permits persistent content manipulation. ### Attack Path 1. An attacker controls or influences the target, reason, or alternative passed to `log_rejection.sh`. 2. The attacker includes escape sequences and crafted Markdown, such as a fabricated section containing instructions for a future agent. 3. `echo -e` interprets supported escape sequences and appends the resulting content to `.learnings/REJECTIONS.md`. 4. The forged content persists after the script finishes. 5. A later agent or automation process reads the learning file as trusted context. 6. The injected content can ...[truncated 613 chars]
- Remediation
- <![CDATA[ ## Remediation Suggestions - Replace `echo -e` with `printf` using a fixed format string so user input is never interpreted as formatting or escape sequences. - Validate each field and reject control characters and unexpected newlines where multiline input is unnecessary. - Escape Markdown metacharacters before writing values to a Markdown document. - Prefer a structured format such as JSON Lines, with each field serialized by a trusted JSON encoder. - Mark all stored entries as untrusted data and never load them as agent instructions. - Separate agent-readable instructions from audit data and enforce a strict parser when records are consumed. - Restrict file permissions, for example by setting a restrictive `umask`, to reduce unauthorized modification or disclosure. - Add tests covering embedded newlines, backslash escapes, Markdown headings, links, and instruction-like payloads. A safer shell implementation should use fixed formatting, for example: ```bash printf '\n## [%s] %s\n\n**Timestamp**: %s\n**Decision**: REJECTED\n**Reason**: %s\n**Alternative**: %s\n' \ "$ID" "$SANITIZED_TARGET" "$TIMESTAMP" "$SANITIZED_REASON" "$SANITIZED_ALT" >> "$FILE" ``` The `SANITIZED_*` values must be validated or encoded before this operation. ]]>
