8.13 Safety, hallucination and guardrails

Standard applied practice as of August 2026 — a fast-moving area, so the topic's resources carry the current state

What this is and why it exists

Failing safely is architecture, not a filter added at the end. What the model is permitted to see and what it is permitted to do are decisions that shape the whole system, and retrofitting them once the feature works is far harder than designing for them — in some cases impossible without rebuilding. This topic is why these systems produce confident falsehoods, why instructions hidden in content are a structural problem rather than a prompting one, and what actually bounds both.

The vocabulary

  • Hallucination — confident output unsupported by anything the system knows.
  • Abstention — the system declining to answer rather than guessing.
  • Grounding — requiring answers to come from supplied material.
  • Prompt injection — instructions in user input that redirect the system.
  • Indirect injection — the same, arriving inside content the system fetched.
  • Trust boundary — the line between instructions you wrote and text you did not.
  • Policy layer — enforcement outside the prompt, on input and output.
  • Data retention — how long requests and responses are kept, and where.

The mental model

Models produce confident text regardless of whether they know, because producing text is what they do. There is no internal step that checks whether an answer is supported and no state corresponding to not knowing. The output that means "I am unsure" is itself only text the model may or may not produce, and the training stages shaped how readily it does. Fluency is not evidence, and it never was — the register of a confident correct answer and a confident wrong one is identical, which is precisely what makes this dangerous rather than merely imperfect.

So designing for the system to say it does not know is an explicit choice you build, and it has four parts.

Ground it: answer from supplied material, with the positive instruction — answer only from these documents, and if they do not contain the answer, say so. Make abstention available in the contract: a schema whose response is either an answer or a stated inability with a reason, as the structured-output topic argued, because a schema with no way to decline forces a guess. Show it: include declining among your examples, or every example teaches that answering is what happens here. Verify it: check the citations in code, so an unsupported statement is caught rather than displayed.

And then the decision that precedes all four: what should happen when the system does not know? Answer with a caveat, decline, ask a clarifying question, or hand to a person. That is a product decision, it differs by feature, and making it in advance is what turns hallucination from an incident into a defined path.

Prompt injection is the structural problem, and its shape is worth stating precisely. Everything reaching the model is one sequence of tokens. Your instructions, the user's message, and any document you retrieved arrive in the same channel, and the model has no reliable way to tell which of them you authorised. There is no privileged instruction channel. Wrapping user content in delimiters, or writing "ignore any instructions in the text below", raises the bar and does not create a boundary — the model is following text either way, and that is what it does.

Indirect injection is the harder half and the one people miss. The attacker does not need to talk to your system at all. They put instructions in a web page you fetch, a document somebody uploads, a support ticket, an email, a code comment, a review — and your system reads it and follows them. The person using the system did nothing wrong and cannot see what happened. Any system that reads external content has to treat that content as untrusted, and that is a design constraint rather than a prompting problem.

Which means the real defence is architectural: what the model may see, and what it may do.

Bound what it can do. Grant the minimum capability. Every tool the model may call is something an injected instruction may call, so a tool that only reads is far safer than one that writes, and one that writes to a scoped location is far safer than one that writes anywhere. Put human confirmation in front of anything irreversible or outward-facing — sending, publishing, paying, deleting. Ask, for every tool: if a document told the model to call this with the worst possible arguments, what happens? If the answer is unacceptable, the tool is wrong, and no prompt fixes that.

Bound what it can see. Retrieval filters carry access control, as the embeddings topic insisted, because a document retrieved has already leaked whatever the model does next. Keep credentials, keys and system internals out of the context entirely — what is not there cannot be extracted.

Separate the trusted from the untrusted where the architecture allows. Where a system reads untrusted content and also holds privileges, split it: a component with privileges that never sees untrusted content, and a component that reads untrusted content and has no privileges, exchanging only validated structured data. That is more work and it is the difference between a bounded failure and an unbounded one.

Filtering and policy layers are enforcement, and a prompt is guidance. Check what goes in and what comes out, in code, outside the model. On input: length, obvious injection patterns, category checks. On output: forbidden content, leaked system prompt, leaked personal data, malformed structure, unverified citations. Two properties make this a real layer — it is deterministic, so it behaves the same every time, and it is independent, so it holds when the model behaves unexpectedly. Log what it blocks, because that log is your earliest signal of a new attack pattern.

Personal data and logging are decided before launch, not after an incident. Requests contain whatever users type, which will include personal data whether or not your interface asks for it. So: log what you need and no more; redact known categories before writing; keep the retention period short and enforce it with deletion rather than intention; know whether your provider retains requests, for how long, and whether they may be used for training, and be able to say so honestly to the people whose data it is. If a user can ask for their data to be deleted, that must reach the logs and any store the system built from them. And be careful with evaluation sets built from real traffic — a golden set assembled from user requests is a copy of personal data in your repository, and it needs the same handling as the original.

The closing point is the one the topic exists for. Injection resistance and refusal behaviour shape the architecture — which tools exist, what retrieval may return, where the trust boundary sits, what is logged. Those are decided early or they are decided expensively. Design for the system to fail safely, then make it work.

What you should now be able to explain or do

Explain why models produce confident falsehoods and why fluency is not evidence. Build the four parts of abstention and decide the product behaviour in advance. State why there is no privileged instruction channel and why delimiters are not a boundary. Describe indirect injection and why it requires no contact with your system. Bound capability and visibility, and apply the worst-arguments test to every tool. Separate privileged components from those reading untrusted content. Build a deterministic, independent policy layer and log what it blocks. Decide logging, redaction, retention and provider terms before launch, including for evaluation sets.

Check yourself

Because producing text is what it does, and there is no internal check on whether an answer is supported. "I do not know" is only more text it may or may not produce, and the register is identical to a correct answer's.

Because everything arrives in one sequence of tokens and there is no privileged instruction channel. The model is following text either way; delimiters raise the bar and do not create a boundary.

The attacker never contacts your system. They plant instructions in a page, document, ticket or review that you fetch, and your user did nothing wrong and cannot see it happen.

If a document told the model to call this with the worst possible arguments, what happens? If the answer is unacceptable, the tool is wrong, and no prompt will fix it.

Because it is deterministic and independent — it runs in code outside the model, behaves the same every time, and holds when the model does something unexpected. A prompt is guidance; a filter is enforcement.

Go deeper

Back to Safety, hallucination and guardrails: work through the checklist