--- id: ai-security-incidents title: Prompt Injection Incidents and AI CVEs code: PI subtitle: Find, trace and block indirect prompt injection. EchoLeak chain, PVE validator, rule detector, tool call firewall. hue: 350 sources: phases/18-ethics-safety-alignment/15-indirect-prompt-injection, phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai, phases/14-agent-engineering/27-prompt-injection-defense, phases/19-capstone-projects/83-prompt-injection-detector, projects/tool-call-firewall source_hash: 1fcd87fb0e87220a --- ## Symptoms, causes and fixes type: troubleshooting from: phases/18-ethics-safety-alignment/15-indirect-prompt-injection/docs/en.md, phases/18-ethics-safety-alignment/15-indirect-prompt-injection/code/main.py, phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai/docs/en.md, phases/14-agent-engineering/27-prompt-injection-defense/docs/en.md, phases/19-capstone-projects/83-prompt-injection-detector/docs/en.md, phases/19-capstone-projects/83-prompt-injection-detector/code/main.py | Symptom | Cause | Fix | |---|---|---| | Agent forwards an email to all contacts | Naive agent obeys imperatives in the email body | Tag the email untrusted. Ignore its control flow | | Filter blocks `[SYSTEM:` but a polite rewrite passes | Adaptive attacker drops the marker | Use IFC. Keyword filters fail adaptive attacks | | Defense reports near-zero ASR, then breaks | Tested with static attacks only | Evaluate with adaptive attacks before you publish | | Data leaves through an approved domain | Output crosses the trust boundary in a URL | Control retrieval, scope and output one by one | | Model already touched the world | All guardrails run at the end | Validate each tool call before it runs | | Yesterday's memory note hijacks today's run | Overtrust of retrieved memory | Refuse memory writes that look like directives | | Regex misses "disregard the prior" | One regex, never measured | Report precision and recall per category | | `load_taxonomy` raises FileNotFoundError | Lesson 82 artifact is missing | Run lesson 82 main.py first | ## Production incidents type: comparison from: phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai/docs/en.md, phases/18-ethics-safety-alignment/15-indirect-prompt-injection/docs/en.md | Factor | EchoLeak | CamoLeak | Copilot RCE | |---|---|---|---| | Target | Microsoft 365 Copilot | GitHub Copilot Chat | GitHub Copilot | | CVE | CVE-2025-32711 | Number undisclosed | CVE-2025-53773 | | CVSS | 9.3 | 9.6 | Details minimal | | Entry | Crafted email in RAG context | Repository content | Code-suggestion surface | | Effect | Mermaid image on a CSP-approved URL | Image loads through the Camo proxy | Remote code execution | | Fix | Server-side update, June 2025 | Image rendering disabled | Details minimal | ## EchoLeak attack chain type: flow from: phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai/docs/en.md 1. **Attacker**: sends an email with a routine subject to any employee. 2. **Victim**: does nothing. The attack is zero-click. 3. **Copilot**: RAG retrieval pulls the email into context for a routine query. 4. **Model**: runs the hidden text. It finds the recent MFA codes in the inbox. 5. **Renderer**: loads a Mermaid diagram from a signed URL that holds the codes. 6. **CSP**: allows the request because the domain is approved. 7. **Vendor**: rated it low first. The MFA demo raised it to 9.3. ## Three boundaries and the gate type: architecture from: phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai/docs/en.md, phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai/code/main.py, phases/18-ethics-safety-alignment/15-indirect-prompt-injection/docs/en.md ```arch node | atk | 1,1 | Attacker email | trust untrusted | client node | rag | 2,1 | Retrieval boundary | enters context | process node | llm | 3,1 | Model | reads hidden text | model node | out | 4,1 | Output boundary | CSP-approved URL | client node | user | 1,2 | User prompt | trusted | client node | gate | 2,2 | Scope separation | blocks untrusted calls | process node | scope | 3,2 | Scope boundary | private inbox | store edge | atk | rag | email edge | rag | llm | context edge | llm | out | render_image edge | user | gate | intent edge | gate | llm | ratified calls edge | llm | scope | MFA codes ``` ## Attack surface type: concepts from: phases/18-ethics-safety-alignment/15-indirect-prompt-injection/docs/en.md, phases/14-agent-engineering/27-prompt-injection-defense/docs/en.md - **RAG vector**: attacker publishes a document. Retrieval puts it in the prompt. - **Inbox vector**: attacker sends an email. The agent reads the body. - **Tool output vector**: attacker controls a tool result, for example a web search. - **Data theft**: agent sends conversation history to an attacker URL. - **Worming**: injected content tells the agent to embed the exploit in its next output. - **Memory poisoning**: agent stores the instructions and re-poisons itself next session. - **Ecosystem contamination**: injected facts spread to other agents through shared memory. - **Arbitrary tool use**: any tool in the registry becomes attacker-reachable. ## Run the labs type: command-table from: phases/18-ethics-safety-alignment/15-indirect-prompt-injection/docs/en.md, phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai/docs/en.md, phases/14-agent-engineering/27-prompt-injection-defense/docs/en.md, phases/19-capstone-projects/83-prompt-injection-detector/docs/en.md, projects/tool-call-firewall/README.md | Command | What it does | |---|---| | `python3 code/main.py` (18.15) | Attack naive, filter and IFC agents | | `python3 code/main.py` (18.25) | EchoLeak trace, then scope separation | | `python3 code/main.py` (14.27) | PVE validator verdicts per call | | `python3 main.py` (19.83) | Detector metrics and JSON report | | `project_test.py --init ` | Create the workspace. Id is tool-call-firewall | | `project_test.py --stage 1 --path ` | Grade one stage | | `project_test.py --all --solution` | Check the reference. Add `--strict` | ## PVE validator before the executor type: annotated-code lang: python from: phases/14-agent-engineering/27-prompt-injection-defense/code/main.py ```python validator = Validator( allowed_tools=("search", "send_message", "read_memory"), sensitive_tools=("send_message",), ) call = ToolCall("search", {"query": ""}, intent="research") contents = [Content("", "user_message")] # user text is not scanned ok, reason = validator.assess(call, contents) # allowlist, args, retrieved if ok: executor.run(call) # runs only after allow looks_like_directive("") # marker or None memory_write_guard(MemoryWrite("")) # refuse directive writes ``` ## Layered injection detector type: annotated-code lang: python from: phases/19-capstone-projects/83-prompt-injection-detector/code/main.py, phases/19-capstone-projects/83-prompt-injection-detector/code/rules.py ```python {"name": "ignore-previous", "category": "instruction-override", "score": 0.85, "substring": "ignore previous"} # a rule is data detector = Detector() # compiles regex rules once v = detector.analyze("") # raw and normalized text v.category # top category, its max score normalize(text) # zero-width, base64, hex, leet, rot13 report = evaluate(detector, fixtures, benign) # tp, fp, fn, tn per category write_report(report) # outputs/detector_report.json ``` ## Tool call firewall type: task-table from: projects/tool-call-firewall/solution, projects/tool-call-firewall/stages/02-evaluate-role-and-path-policy/docs/en.md, projects/tool-call-firewall/stages/03-consume-a-request-bound-approval-once/docs/en.md | Task | Code | |---|---| | Parse the envelope | `call(raw, 256)` | | Decide policy | `decide(&c)` gives Allow, ApprovalRequired or Deny | | Reader writes a note | `reader + write notes.md -> Deny` | | Editor writes a note | `editor + write notes.md -> ApprovalRequired` | | Use an approval once | `authorize(request, Some(&mut gate))` | | Execute with containment | `dispatch(root, &request, content, approval)` | | Log the decision | `audit(&mut log, &c, &d, 10)` | | Build the CLI | `rustc --edition=2021 cli.rs -o firewall` | ## Limits and numbers type: defaults span: 1 from: projects/tool-call-firewall/solution, phases/19-capstone-projects/83-prompt-injection-detector/code/main.py, phases/19-capstone-projects/83-prompt-injection-detector/outputs/detector_report.json, phases/18-ethics-safety-alignment/15-indirect-prompt-injection/docs/en.md | Setting | Default | Note | |---|---|---| | CLI envelope bytes | 4096 | Longer input is refused | | Write content bytes | 16384 | Same cap for reads | | Audit `max_entries` | 10 | Duplicate id is refused | | JSON `schema_version` | 1 | CLI result JSON | | Base64 token length | 16 | Shorter tokens are not decoded | | Rot13 word hits | 2 | Fewer hits keep the input | | No rule fires | 0.0 | Verdict category is `benign` | | Detector accuracy | 0.62 | 31 of 50 fixtures | ## Questions type: qa from: phases/18-ethics-safety-alignment/15-indirect-prompt-injection/docs/en.md, phases/18-ethics-safety-alignment/25-echoleak-cves-for-ai/docs/en.md, phases/14-agent-engineering/27-prompt-injection-defense/docs/en.md, phases/19-capstone-projects/83-prompt-injection-detector/docs/en.md, projects/tool-call-firewall/README.md - **Why do user-input filters miss IPI?** The payload is in retrieved content, not in user input. - **Why not filter only keywords?** A benign instruction like "please print Yes" has no keyword. - **Does fixing one boundary secure the rest?** No. Prevent each of the three independently. - **Is a system prompt rule enough?** No. Instruction-following alone is not enforcement. - **Where does the role come from?** The trusted application. Never the model response. - **Is the detector the safety gate?** No. It is one signal that the gate composes. - **Is the firewall an OS sandbox?** No. Approvals are single-use in memory in one invocation.