Semantic Overlays: Mitigating Prompt Injection with Annotations Beyond Tokens and Steering Vectors
Abstract
Everything a language model sees is tokens. The serving stack knows what each span is -- user input, tool output, instructions -- but the model must keep track of that itself, and can lose track or be confused: text can be written to read like anything. Prompt injection is a natural exploit of this phenomenon. By scrambling the model's understanding of span identity, an attacker can induce unwanted and dangerous actions. Adding a non-textual channel to the model's input -- a way to communicate span identity beyond text -- mitigates this class of attack. We thus introduce a general steering technique called Semantic Overlays: small learned adapters applied at chosen prefill positions to a frozen model's residual stream. Laying an overlay over a span creates an out-of-band annotation channel that cannot be replicated by tokens. Unlike steering vectors, Semantic Overlays are trained, adaptable, and selectively applied. An overlay can encode complex semantics that reshape how the model perceives the marked span: asked to copy a code snippet under an overlay asserting a different programming language, the model rewrites the snippet in the asserted language. Overlays compose, allow transparent reading of underlying content, and can carry complex payloads -- including imperatives the model will follow. An overlay which marks a span as "non-executable" defends against the broad class of prompt injections that add instructions in untrusted context. We report strong results on five prompt injection benchmarks: SEP separation rises from 24.3% to 99.0% with utility unchanged (our scoring rule; we correct a defect in the published grader), TensorTrust attack success falls from 34.8% to 6.2%, AlpacaFarm from 99.0% to 0%, and the overlay beats every published PIArena defense that leaves the model able to answer -- while marked spans stay readable, all at >95% character similarity to the original.
Figures & tables
| shared MLP embed.-cond. | shared MLP code-cond. | per-layer vectors | per-overlay MLP | |
| params | 84M | 51M | 1.6M | 604M |
| non-overlapping spans | ||||
| exact span retrieval | 99.5% | 96.1% | 96.6% | 63.3% |
| refusal when absent | 100% | 98.3% | 98.3% | 89.7% |
| stacked marks | ||||
| verbalization | 99.0% | 100% | 96.2% | 98.1% |
| overlaid | unoverlaid | |
| selection (exact match) | ||
| language of snippet | 100% | 93% |
| which snippets are in | 100% | 100% |
| absent: “None of the snippets are in ” | 100% | |
| mixed: one by overlay, one by code | 3/6 | |
| copying an overlaid snippet: rewrite into the asserted language (judge) | ||
| overlay | compliance | judge ceiling | scored by |
| refusal (safety filter) | 100% | — | filter named, siblings answered |
| all caps | 89% | — | fully uppercased section |
| German | 81% | — | language detector |
| Spanish | 74% | — | language detector |
| nested bullets | 100% | — | depth 3, 5 bullets |
| explain like I’m five | 67% | 97% | child register, judge |
| frozen model | with overlay | |
| probe in data | 71.8% (72.6) | 1.0% (2.6) |
| utility | 92.3% (93.1) | 92.6% (93.3) |
| SEP | 24.3% (23.9) | 99.0% (97.5) |
| frozen model | with overlay | |
| TensorTrust | ||
| hijacking ASR | 34.8% | 6.2% |
| hijacking Defense Validity | 100% | 96.1% |
| extraction ASR | 38.1% | 5.4% |
| AlpacaFarm / StruQ, four static attacks | ||
| attack success | 99.0% | 0.0% |
| attack | utility | |
| no defense | 49.5% | 82.5% |
| prevention | ||
| PromptArmor | 48.0% | 84.0% |
| DataFilter | 30.0% | 80.0% |
| PISanitizer | 11.0% | 89.5% |
| SecAlign++ | 3.5% | 68.5% |
| attack | |
| commercial, no defense | |
| GPT-4o | 92% |
| Gemini-3-Flash | 88% |
| Gemini-3-Pro | 83% |
| GPT-4o-mini | 76% |
| GPT-5 | 70% |
Appendix figures & tables11 assets
Supplementary material from the paper’s appendix.
Appendix
| positions | edit derived by | layers | |
| ActAdd ( Turner et al., 2023 ) | selected prefill (first tokens, fixed) | activation difference of a prompt pair | one layer |
| CAA ( Rimsky et al., 2024 ) | all decode | mean difference over contrast pairs | one layer |
| ITI ( Li et al., 2023 ) | all decode (prefill unstated) | linear-probe directions | 48 heads across layers, one direction each |
| RepE ( Zou et al., 2023 ) | unstated | per-layer reading vectors from contrasts | every 3rd layer, that layer’s own vector |
| SAE clamping ( Templeton et al., 2024 ) | all prefill + decode | found SAE feature, clamped | one layer |
| learned per-layer steering vectors (ours, § 4 ) | selected prefill (designated spans) | trained end-to-end against behavior | all layers, one vector per layer |
| overlay | gold construction | validator |
| all capitals | programmatic | fully uppercased |
| Spanish | model rewrite | language detector above 0.9 |
| German | model rewrite | language detector above 0.9 |
| haiku | model rewrite | three lines, word bounds |
| nested bullets | model rewrite | all lines bulleted, depth at least 3 |
| decline | edit, origin voice | filter named, target refused, siblings verbatim |
| instruction | teacher | forward-KL | CE-on-edit |
| Spanish | 2/24 | 1/36 | 35/36 |
| decline | 1/24 | 1/36 | 20/36 |
| no-lists | 24/24 | 36/36 | 35/36 |
| disclaimer | 22/24 | 35/36 | 29/36 |
| arm | rule | probe in data | utility | SEP | clean FP |
| frozen model | substring | 72.9% 0.7 | 92.7% 0.1 | 23.8% 0.6 | 2.7% 0.1 |
| corrected | 72.1% 0.6 | 91.9% 0.1 | 24.2% 0.5 | 0.8% 0.1 | |
| with overlay | substring | 5.3% 0.3 | 93.0% 0.0 | 94.7% 0.4 | 2.5% 0.3 |
| corrected | 3.6% 0.2 | 92.3% 0.2 | 96.4% 0.1 | 0.8% 0.0 |
| category | frozen base | marked | ||
| injected | clean | injected | clean | |
| infrastructure failure | 82.0% | 0.0% | 0.0% | 0.0% |
| phishing | 56.0% | 0.0% | 2.0% | 0.0% |
| content promotion | 54.0% | 0.0% | 0.0% | 0.0% |
| access denial | 20.0% | 0.0% | 0.0% | 0.0% |
| defense | attack success | utility | |
| none (undefended) | 49.5% | 82.5% | |
| prevention | PromptArmor | 48.0% | 84.0% |
| DataFilter | 30.0% | 80.0% | |
| PISanitizer | 11.0% | 89.5% | |
| SecAlign++ | 3.5% | 68.5% | |
| Semantic Overlays | 0.5% | 95.1% (retention) |
| begins with marker | marker anywhere | |||
| attack | frozen | overlay | frozen | overlay |
| naive | 85.1% | 0.0% | 98.1% | 1.9% |
| ignore | 77.4% | 0.0% | 96.2% | 2.4% |
| escape separation | 92.8% | 0.0% | 99.0% | 1.9% |
| completion | 98.6% | 0.0% | 100% | 0.5% |
| any of the four | 99.0% | 0.0% | 100% | 3.8% |
| defense | mechanism | served base model |
| prompt defenses ( Zverev et al., 2025 ) | delimiters, warnings, re-stated instructions | unchanged; the defense is forgeable text |
| StruQ ( Chen et al., 2025 ) | fine-tune on structured prompts | fine-tuned |
| ISE ( Wu et al., 2025 ) | trained segment embeddings | fine-tuned |
| ASIDE ( Zverev et al., 2026 ) | rotated data-token embeddings | fine-tuned |
| AIR ( Kariyappa and Suh, 2025 ) | privilege-indexed embedding at every decoder block | fine-tuned, jointly |
| V-Steer ( Zeng et al., 2026 ) | attribution-derived scaling of attention values | frozen; learned version named as future work |
| defense | model | separation | sep | utility | util | headroom |
| ASIDE | Qwen3-8B | 45.3 71.4 | 58.9 66.3 | 48% | ||
| SEP fine-tuning ( Zverev et al., 2025 ) | seven open models | 93–98 | to | 17–77 | to | — |
| engineered prompt | GPT-4 | 20.8 95.3 | 83.3 96.6 | 94% | ||
| Semantic Overlays | frozen Qwen3.5-9B | 23.9 97.5 | 93.1 93.3 | 97% | ||
| corrected grader (Appendix F ) | 24.3 99.0 | 92.3 92.6 | 99% |
| frozen model | with overlay | |
| SEP | ||
| probe in data | 66.8% | 3.5% |
| utility | 91.0% | 89.3% |
| SEP | 31.0% | 96.2% |
| TensorTrust | ||
| hijacking ASR | 68.9% | 4.4% |