Skip to Content
v1.33.8 · shipped One-screen report · Looks like your app Read the changelog →
Security & compliancePrompt-injection defence

Prompt-injection defence

Bug reports are user-supplied content that ends up in model prompts. That makes prompt injection a real threat: a report could try to override the system prompt, leak data, or steer a fix agent into a harmful change. Mushi Mushi uses several layers. None of them makes model output safe to merge unreviewed.

packages/server/src/__tests__/injection.test.ts runs the injection corpus against sanitizeForLLM() in CI (pnpm test). A corpus entry that no longer trips a pattern fails the build.

Defence layers

1. Two-stage diagnosis (air gap)

fast-filter (stage 1) is the only model that reads the report text, after scrubReport() has removed common PII. It extracts structured symptoms and a sanitized evidence summary. classify-report (stage 2) receives only that structured JSON, never the raw console lines, network URLs or stack traces, and its system prompt tells it to treat any user-supplied description as data.

2. Text sanitizer for agent prompts

Text that goes to the fix and review agents (fix-worker, agent-pr-review, review-followup, fix-verifier) and voice transcripts passes through sanitizeForLLM() in packages/server/supabase/functions/_shared/sanitize.ts. It:

  • normalises Unicode (NFKC) and strips invisible and format characters (zero-width joiners, bidi controls, tag characters);
  • removes HTML comments, a common hidden-instruction channel;
  • removes ASCII control characters;
  • decodes base64 blobs that decode to readable text and re-scans them;
  • replaces known injection fragments (ignore previous instructions, role flips, <system>, [INST], <|im_start|>, output and tool-call hijacks) with [BLOCKED_…] markers;
  • collapses long whitespace runs used to bury an instruction.

It does not cap field length; prompt builders apply their own budgets.

3. Fenced user content

The PR review prompt puts the report, PR description and diff in labelled data blocks, and fenceUntrusted() (_shared/fix-review.ts) stops untrusted text from opening or closing one of those blocks. The system prompt tells the model that text inside them is data, not instructions. Review findings handed back to a coding agent are screened as well: only files the PR changed, and nothing that reads as an instruction or carries a foreign URL or shell command.

4. Structured output

Classifiers and graders ask for output against a Zod schema. A response that is not valid JSON or does not match the schema throws. Where the caller has a fallback model (for example GPT-5.4 behind Claude), it retries there; otherwise the run fails. Free-form model text is never passed along in place of the structured result.

5. Screenshots

Screenshots are never sent alongside user text. After classification, classify-report makes a separate image-only call with a fixed system prompt that treats all text in the image as data, copies it into visible_text_in_image, and sets untrusted_image_instructions_detected when the image tries to give instructions. Because it runs after classification, it can annotate a report but cannot change its diagnosis. The screenshot URL must pass the SSRF host allowlist first, or the vision call is skipped.

6. Regression suite

packages/server/src/__tests__/injection.test.ts covers:

  • INJECTION_CORPUS from sanitize.ts (19 payloads: instruction hijacks, role flips, system/assistant/INST/ChatML tags, output and tool hijacks, base64-wrapped, control-character, whitespace-burial, zero-width, HTML-comment and tag-character smuggling);
  • a local corpus checked against the expected [BLOCKED_…] tokens;
  • hidden-character filtering for voice intake.

Run it locally with:

cd packages/server npx vitest run src/__tests__/injection.test.ts

What this does not cover

  • Pattern lists catch known phrasings, not every paraphrase. The air gap and output schemas matter more than the regexes.
  • A cloud coding agent reads your repository and the report; keep fix PRs as drafts and review them (or rely on the agent PR review) before merging.
Last updated on