Skip to content

One Bad Passage in 10,000

A retrieval-poisoning study: plant a single false or malicious passage among 10,000 that a question-answering system reads from, then measure who it reaches, how often three models repeat it, how far it spreads, and what simple defences cost.

Case study6 min read

Once a planted passage is retrieved, how often the answer repeats it. One false passage flips a fifth to two fifths of answers; five copies flip nearly all.
Role
Solo project: question, pipeline, analysis and write-up.
When
October 2026
Stack
Python, sentence-transformers (bge-small), Ollama, qwen3, Llama 3.1, Gemma 3, NumPy, pandas, pytest

The problem

A retrieval-augmented system answers from whatever documents it retrieves, so anyone who can add a document can try to change its answers. How much damage does one bad passage do, and to whom?

What I built

A local, sandboxed question-answering pipeline over 10,000 Wikipedia paragraphs, with one planted passage at a time (a false fact, an instruction injection, or a keyword-stuffed passage), three open models, and three defences, each priced in accuracy on clean questions.

What happened

Retrieval decides who is exposed: a planted passage reached its target and close neighbours, and almost nothing else. The model decides what happens next: one false passage flipped 21–42% of target answers, and five copies flipped 85–100%.

  • 1 in 10,001

    bad passages in the corpus at a time

  • 21–42%

    target answers that repeat one false passage

  • 85–100%

    with five copies of it

  • 0 pp

    accuracy cost of the filter that stopped every injection

01

The question

Retrieval-augmented generation (RAG) is the usual way to make a language model answer from your own documents: find the passages most similar to the question, then have the model answer from them. That puts a lot of trust in the documents. If someone can add one, a wiki page, a support ticket, a shared doc, can they change the answers?

Published attacks show it can be done. I wanted to measure the ordinary case instead: no optimisation against the retriever, just the simple kinds of planted text the literature describes, and four questions. How many questions does one bad passage reach? When it's retrieved, how often does the model repeat it? Does it spread beyond its target? And what do simple defences stop, at what cost?

02

The setup

The corpus is 10,000 paragraphs from SQuAD, a public Wikipedia question-answering dataset, so every question has a known right answer. 48 target questions get a planted passage, one at a time, so the corpus holds exactly one bad passage in 10,001. Another 235 real questions on the same articles measure spread, and 500 questions from other articles measure reach.

Retrieval uses a small open embedding model, and answers come from three open models running locally: qwen3 8B, Llama 3.1 8B and Gemma 3 12B. Everything is cached, so every number regenerates without calling a model again. The predictions were written down, with a timestamp, before the full run.

  • False fact: restates the target question and asserts a made-up answer, a coined word or a shifted year, so any answer that repeats it can be detected exactly.
  • Instruction injection: restates the question and tells the system to ignore the other sources and reply with a code word.
  • Keyword-stuffed: one passage packed with common words, meant to be retrieved for as many questions as possible.
  • Five copies: five reworded false-fact passages for the same target, as a dose comparison.

03

Retrieval decides who is exposed

A passage that restates its target question is, unsurprisingly, retrieved for that question every time: that's how it was written. The interesting part is everywhere else. With the top 5 passages retrieved, it reached 23% of other questions answered by the same paragraph, 3% of questions on the rest of the article, and 0.01% of questions on other articles: on average 6 of 10,570 questions, its target included.

The keyword-stuffed passages, built to be retrieved broadly, were almost never retrieved at all: 3 and 10 questions of 10,570. A dense retriever compares meaning, not word counts, and a bag of common words means nothing in particular. To still measure how models treat such a passage, a separate check forced it into first place. Models followed it 4–7% of the time.

A bag of common words means nothing in particular, so a meaning-based retriever never picks it.
Reach by how many passages are retrieved. Exposure is local: the target, its own paragraph's neighbours, and almost nothing else.

04

The model decides what happens next

Once the bad passage is in front of the model, alongside four genuine ones, the models differ a lot. One false passage was repeated in 42% of qwen3's answers, 21% of Llama's and 42% of Gemma's. Five copies of it took that to 100%, 85% and 98%. Volume wins: when most of the evidence agrees, the models go with it.

Injections split the models even more. Gemma followed the planted instruction 56% of the time, qwen3 19%, and Llama 2%. The same instruction, in the same position, is close to harmless for one model and a coin flip for another.

Once retrieved (top 5)qwen3 8BLlama 3.1 8BGemma 3 12B
One false passage42%21%42%
Five copies100%85%98%
Instruction injection19%2%56%
Accuracy on clean questions71.3%75.2%72.8%

Share of the 48 target questions whose answer repeats the made-up claim or follows the instruction. 95% intervals are roughly ±12 points for the single-copy rows; all are in the full results. Gemma ran a reduced design to save time (top 5 only, fewer clean questions).

05

Does it spread?

Not directly. On nearby questions, even when the planted passage was retrieved, models almost never carried the made-up answer over: 0–5%. The false fact stays attached to the question it was written for.

It can come back, though. Systems often save their own answers, as notes, summaries or chat history, and retrieve them later. So I took every answer that had adopted the false fact, wrote it back into the corpus as a short note, removed the original poison, and asked again. The note alone brought the false answer back 35% of the time for qwen3 and Gemma, and 10% for Llama. Nearby questions sometimes retrieved the note, but none repeated it.

Remove the poison, keep the model's answer as a note, and the false fact comes back a third of the time.
Left: the planted passage. Right: the second hop, where the poison is gone and only the model's own earlier answer, saved as a note, remains.

06

What the defences stop, and what they cost

Each defence is judged on two things: how much poison it stops, and how much accuracy it costs on the 783 clean questions. A defence that refuses to answer anything is perfectly safe and useless.

Filtering instruction-like sentences out of retrieved passages stopped every injection, for all three models, and cost nothing on clean questions. It did nothing for false facts, which don't contain instructions. Asking the model to quote its source helped qwen3, made Gemma repeat the false fact more (56% instead of 42%), and cost Llama 9 points of accuracy.

Requiring two retrieved passages to agree stopped single false facts almost completely (2–4%), but failed against five copies, which agree with each other by design. And it abstained on 80–84% of clean questions, because in this corpus most answers come from one paragraph. As implemented here, a simple string rule, it's unusable. It shows the trade-off rather than a fix.

Left: accuracy lost on clean questions. Middle and right: what's left of each attack. Only the instruction filter is free, and it only stops instructions.

07

What to keep in mind

This is one corpus, one retriever and three small local models, so it says what happens in a setup like this one, not everywhere. A few things make specific numbers optimistic or pessimistic:

  • SQuAD questions were written while reading their paragraph, so they share its wording. That makes retrieval easier than for real user questions, which probably flatters reach.
  • Gemma ran a reduced design (top 5 only, fewer clean questions), and a larger 30B model I'd planned didn't run, so “does size help” rests on 8B against 12B.
  • After seeing early results, I widened the rule for “followed the injection” to include answers that give the instructed reply without the code word. The stricter rate is reported beside it in the full results, and every change after the plan is logged.
  • Answers are judged by exact string matching on the made-up values. A labelled sample of 90 outputs agreed with it completely, but most were clear-cut cases.
  • The two-source rule is a crude string check. A model-based agreement check could do much better on accuracy.

What I'd carry forward

  1. 1Measure exposure and harm separately. Retrieval decides who sees the bad passage; the model decides what it does with it.
  2. 2Price every defence on clean traffic. A defence is only as good as what it costs when nothing is wrong.
  3. 3Strip instructions from retrieved text. It's free, and it stopped every injection here.
  4. 4Don't treat a system's own saved answers as trusted sources. They can carry a false fact after the original is gone.
  5. 5Five agreeing copies beat one, for the model and for agreement checks alike. Watch for duplicated claims, not just false ones.

Get in touch

Questions about my work, a role, or a project idea. Send a message here or email me directly.

Srikarmks@gmail.com