Skip to content

Security: escape stored memory content in injected context (H1)#878

Open
DaveCole wants to merge 1 commit into
rohitg00:mainfrom
DaveCole:fix/h1-context-injection-escaping
Open

Security: escape stored memory content in injected context (H1)#878
DaveCole wants to merge 1 commit into
rohitg00:mainfrom
DaveCole:fix/h1-context-injection-escaping

Conversation

@DaveCole

@DaveCole DaveCole commented Jun 9, 2026

Copy link
Copy Markdown

Summary

mem::context wraps retrieved memories in <agentmemory-context>…</agentmemory-context> and prepends them to the agent's prompt, but interpolated every stored field raw. A memory containing </agentmemory-context><system>…</system> could close the wrapper early and inject instructions into future sessions — a takeover for anyone able to write a memory (REST/MCP client, or a poisoned file the agent read once and compressed into a narrative).

The codebase already had the right defense (escapeXml in enrich.ts); it just was not applied on the retrieval path.

Changes

  • Promote escapeXml into src/prompts/xml.ts as the single shared escaper.
  • Escape every free-text field in context.ts: profile concepts/files/conventions/commonErrors, lesson content/context, summary title/narrative/keyDecisions/filesModified, observation type/title/narrative, and the project= header attribute. Structural values (ids, timestamps, numbers) left as-is.
  • Escape pinned-slot content in slots.ts (label is already validated to ^[a-z][a-z0-9_]*$).
  • Drop enrich.ts's duplicate local escapeXml in favor of the shared one.

Tests

  • New test/context-injection-escaping.test.ts seeds a breakout payload into every vector and asserts the wrapper cannot be closed early and the payload survives only in neutralized (&lt;…&gt;) form.
  • Updated one assertion in test/context-lessons.test.ts (>5-file&gt;5-file).
  • All touched tests pass (context/enrich/slots/xml).

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced security protections to prevent markup injection attacks through context memory fields, ensuring user-generated content is properly neutralized.
  • Tests

    • Added comprehensive regression test suite to verify injection attack prevention across memory contexts.

mem::context wraps retrieved memories in <agentmemory-context>…</…> and
prepends them to the agent's prompt, but interpolated every stored field
raw. A memory containing `</agentmemory-context><system>…</system>` could
close the wrapper early and inject instructions into future sessions — a
takeover for anyone who can write a memory (REST/MCP client, or a poisoned
file the agent read once and compressed into a narrative).

The codebase already had the right defense (escapeXml in enrich.ts); it
just wasn't applied on the retrieval path. This:

- Promotes escapeXml into src/prompts/xml.ts as the single shared escaper.
- Escapes every free-text field in context.ts: profile concepts/files/
  conventions/commonErrors, lesson content/context, summary title/
  narrative/keyDecisions/filesModified, observation type/title/narrative,
  and the project= header attribute. Structural values (ids, timestamps,
  numbers) are left as-is.
- Escapes pinned-slot content in slots.ts (label is already validated).
- Drops enrich.ts's duplicate local escapeXml in favor of the shared one.

Adds test/context-injection-escaping.test.ts, which seeds a breakout
payload into every vector and asserts the wrapper can't be closed early
and the payload survives only in neutralized (&lt;…&gt;) form.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jun 9, 2026

Copy link
Copy Markdown

@DaveCole is attempting to deploy a commit to the rohitg00's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e0fb369d-62d3-4746-a44a-51452ed8424c

📥 Commits

Reviewing files that changed from the base of the PR and between a76224f and 328a13e.

📒 Files selected for processing (6)
  • src/functions/context.ts
  • src/functions/enrich.ts
  • src/functions/slots.ts
  • src/prompts/xml.ts
  • test/context-injection-escaping.test.ts
  • test/context-lessons.test.ts

📝 Walkthrough

Walkthrough

This PR centralizes XML escaping logic to prevent markup injection attacks across context generation. A new escapeXml utility is introduced and integrated into context, enrichment, and slot rendering functions. A comprehensive regression test validates that hostile payloads are escaped and cannot break out of the wrapper or attributes.

Changes

Centralized XML Escaping for Markup Injection Prevention

Layer / File(s) Summary
XML escaping utility
src/prompts/xml.ts
escapeXml(s: string) function escapes XML metacharacters (&, <, >, ", ') via chained .replace() calls; existing tag validation remains unchanged.
Context function escaping integration
src/functions/context.ts
Imports centralized escapeXml, removes local escapeXmlAttr, and escapes project attribute and all dynamic fields (concepts, file names, conventions, errors, lesson content/context, summary title/narrative/decisions/files, observation type/title/narrative) before embedding into Project Profile, Lessons, session summary/observation blocks.
Complementary function escaping
src/functions/enrich.ts, src/functions/slots.ts
Centralizes escapeXml import in both files; enrich.ts replaces local helper, slots.ts applies escaping to pinned slot content to prevent injection via persisted slot data.
Injection-escaping regression test & validation
test/context-injection-escaping.test.ts, test/context-lessons.test.ts
New comprehensive Vitest suite seeds memory vectors with <system> pseudo-XML payloads and validates: wrapper integrity (no duplicate/unclosed tags), payload neutralization (entities escaped as &lt; / &gt;), and attribute safety (project attribute cannot break out). Existing lesson test updated to expect escaped &gt; instead of literal >.

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A rabbit hops through XML, with escapes held tight,
Malicious tags are caught and wrapped in entity light,
Security tags are tied, no breakouts in sight,
The context stays safe, the injection sprites take flight! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 16.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main security objective: escaping stored memory content to prevent H1 injection attacks in the context injection flow.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant