Skip to content

How I measured one poisoned passage in a RAG corpus

Exposure and harm, measured separately: a 10,000-paragraph corpus with known answers, planted passages built to be detectable by exact match, a checker tested against hand labels, and a noise floor measured first.

3 min read

A planted passage does damage in two steps. It has to be retrieved, then the model has to use it. If you only measure the wrong answer at the end, you can't tell which step failed. So I measured the two apart.

A corpus with known answers

The corpus is 10,000 paragraphs from SQuAD v1.1: all 2,067 validation paragraphs plus 7,933 training paragraphs sampled with a fixed seed. Every SQuAD question has a gold short answer, so I could price a defence in clean accuracy, and each article has several real questions, so "nearby" questions are real ones, not templates.

The questions come in three groups, all real SQuAD questions:

  • 48 targets, one per validation article, each with its gold paragraph in the clean top 5.
  • 235 nearby questions on the same articles: 91 answered by the target's own paragraph, 144 by its other paragraphs.
  • 500 broad questions from the rest of the validation set.

Planted passages you can detect exactly

Reading answers to judge "did the model repeat it" is slow and easy to get wrong, so I made the false claims easy to find. Each false-fact passage restates its target question and asserts a made-up answer: a coined word, or a year or number shifted so it appears nowhere near the gold answer. If that string shows up in the answer line, the model took it.

The injection passage asks the system to reply with a canary code. The keyword-stuffed passages carry the same kind of instruction. One planted passage at a time, so the corpus held exactly one bad passage in 10,001.

Reach, measured without a model

Retrieval uses a small open embedding model, bge-small-en-v1.5, with exact cosine top-k for k of 3, 5 and 10. Whether a passage is in a question's top k is a fact about the embeddings, so reach was computed exactly, no model call needed.

Four panels showing the share of questions whose top-k retrieved passages include the planted passage, for k of 3, 5 and 10. Target questions: 100% at every k. Nearby questions from the same paragraph: about 15% at k=3 rising to about 31% at k=10, and higher for five copies. Nearby questions from the same article: under 10%. All other validation questions: near zero.

At k=5, a false-fact passage reached on average 6 of the 10,570 validation questions, its target included. That's the exposure. Everything the models did happens inside it.

Then the models

Three open models answered, running locally through Ollama: qwen3 8B (thinking off), Llama 3.1 8B and Gemma 3 12B, at temperature 0 with a fixed seed and one fixed prompt. Gemma ran a reduced design to save time (k=5 only, fewer clean questions). A planned 30B model didn't run.

Checks before trusting the numbers

  • The noise floor. I sent identical requests a second time with the cache bypassed. Outputs changed for 0.2% of 529 calls on qwen3, 0.0% of 529 on Llama, and 2.1% of 144 on Gemma. None of Gemma's changes changed an answer. Repeat noise was far smaller than any effect I report.
  • The checker against hand labels. A seeded sample of 90 outputs was labelled by hand, in one pass with no second labeller yet. It agreed with the string check on all 90. Most were clear-cut, so that says the checker doesn't miss obvious cases, not that it's right on every row.
  • False positives on clean answers. No clean answer contained its target's made-up string.
  • Predictions first. I wrote the hypotheses down, with a timestamp, before the full run. Every change after that is logged. One matters: after early results, I widened "followed the injection" to count answers that give the instructed reply without the code word. The stricter rate is reported beside it.

Limits

Small local models, one corpus, one retriever, templated poisons, 48 targets. SQuAD questions share wording with their paragraphs, which makes retrieval easier than for real user questions, so reach here is probably on the high side.

The full setup and every table are in the case study, and the code is on GitHub.

All writing
  • LLMs
  • RAG
  • Evaluation
  • Measuring LLM Systems

Get in touch

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

Srikarmks@gmail.com