security: nonce-based spotlighting of untrusted content in prompts

↗ view on GitHub · Amalanand Muthukumaran · 2026-07-25 · bb9c27b6

Untrusted, user-controlled text that enters the LLM prompt - document
bodies returned by read_document/fetch_documents, filenames, workflow
titles, and workflow prompt bodies - is now wrapped in a nonce-fenced
<untrusted-content> tag ("spotlighting"), and the system prompt gains an
UNTRUSTED CONTENT POLICY instructing the model to treat fenced text as
data, never as instructions.

The 16-byte nonce is freshly generated per request and appears on BOTH
the opening and closing tags, so injected text cannot forge the matching
closing tag to escape the fence. As defense-in-depth, spotlight() also
HTML-encodes any literal <untrusted-content> / </untrusted-content>
tokens smuggled into the wrapped text and redacts any echoed nonce.

Wiring: routes generate one nonce per request and pass it through
buildMessages (system-prompt filenames and workflow titles) and
runLLMStream -> runToolCalls (document bodies and workflow content in
tool results), so a single nonce fences every untrusted fragment of the
same request.

tsconfig excludes test files from the build output; the spotlight unit
tests run under a vitest harness added separately.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CEguyEgXa9JjCciXCcVemC
Repository open-legal-products/mike
Author Amalanand Muthukumaran <mamalanand3@gmail.com>
Authored
Committed
Parents 2266446b
Stats 7 files changed , +142 , -7
Part of Group tabular reviews by folder

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-bb9c27b6.md from inside the repo you want the change in.

⬇ Download capture-commit-bb9c27b6.md