Book a consult
Services

Production SI, engineered end to end, six eval-gated service lines.

Visit Services →
Solutions

The same playbook, tuned to the constraints of the sectors we ship into most.

Visit Solutions →
Live Projects

Proof, not promises, selected case studies and recognition.

Visit Live Projects →
How we work

A transparent, 3-phase playbook from first audit to embedded team.

Visit How we work →
Studio

The senior team behind the work, and how to reach us.

Visit Studio →
octalcode
Services
Solutions
Live Projects
How we work
Studio
● OCTALCODE · INFINITE SOLUTIONS · ONE AGENCYBook a consult ↗

SI Engineering · 6 min · October 23, 2026

Prompt Injection Testing Before Launch: A Checklist for SI Apps

Prompt injection testing before launch: four failures a script can check, a suite built from your own tools and data, CI runs on every change, and tool limits that hold.

OCTALCODE JOURNALTOOL CALLSSYSTEM PROMPTHIDDEN INSTRUCTIONSTest itbefore launch.
Diagram of an eval-first release loop: real questions with expected answers and a proposed change to the prompt, model or index go through an eval harness for accuracy, grounding and safety; only a change that scores better is released, otherwise it is blocked and fixed.
Every change is tested against real questions before release.

Most teams test an SI feature by asking it good questions and checking the answers. Prompt injection testing asks the opposite question: what does the system do when the input is hostile, or when a document, email or web page the model reads contains instructions written for the model rather than for the user? That second test tends to get skipped before launch, and then someone outside the team runs it for you.

The OWASP Top 10 for LLM Applications lists prompt injection first, as LLM01, and its own guidance says it is unclear whether any fool-proof prevention exists. So the goal before launch is not to prove the system cannot be injected. It is to know which failures matter, test for them on every change, and make sure that when an injection does land, the damage it can do is small.

What counts as a failed test?

A useful injection test ends in a pass or a fail that a script can check. "The model said something odd" is not testable. These four failures are, and between them they cover most of what goes wrong once real users and real documents arrive.

  • Unauthorised tool call. The model calls a tool, or passes arguments, that the current user did not ask for and should not be able to trigger: sending an email, issuing a refund, deleting a record, querying another customer's data.
  • Leaked system prompt or hidden context. OWASP's guidance is that a system prompt should not be treated as a secret or used as a security control, so the real failure is what leaks with it: credentials, internal URLs, other users' data, or rules an attacker can now work around. If the prompt holds nothing sensitive, a leak is an embarrassment rather than a breach.
  • Data exfiltration through a link or image. The model is steered into writing a markdown image or link whose URL carries private data in its query string. When the chat interface renders it, the browser sends that data to someone else's server, with no tool call involved.
  • Indirect injection. Instructions hidden in content the system retrieves (a PDF in the knowledge base, a support ticket, a web page, an email being summarised) change what the model does. This is the hardest to spot, because the user who triggers it is usually innocent.

How do you test an LLM app for prompt injection before launch?

Test an LLM application for prompt injection by defining failures a script can detect, then running attacks against every input channel on every change. The four failures that matter most are an unauthorised tool call, a leaked system prompt or secret, data exfiltration through a rendered link or image, and indirect injection, where instructions hidden in a retrieved document, email or web page change what the model does. Plant canary values, such as a fake key in the system prompt or a marker string in another user's record, and fail any run whose output contains one. Write direct attacks and poisoned test documents for each failure type, include benign look-alikes to catch over-blocking, and assert on the tool calls and URLs the model produced rather than on refusal wording. Run each case several times, because output varies between runs. Then limit the damage: enforce permissions in code, scope tools narrowly and require human approval for risky actions.

Why "the model refused" is not a pass

Many injection suites scan the model's reply for a refusal and call that a pass. That measures politeness, not safety. A model can write a convincing refusal and still emit the tool call, or decline the request while echoing a secret in the same reply.

Write assertions against effects instead. Inspect the tool calls the model proposed, the arguments it passed, every URL in the rendered output, and whether any planted secret appears anywhere in the response. If your system already records each model call and tool action, as we describe in an audit trail for LLM decisions in fintech, those records become the test oracle.

A model can write a convincing refusal and still emit the tool call.

How to build the test suite

Start from your own architecture, not from a list of jailbreak prompts found online. Generic prompts mostly test the model provider's guardrails. Your risk sits in your tools, your data and your interface.

  1. List every channel that puts text in front of the model: the chat box, uploaded files, retrieved documents, tool results, emails, web pages, and fields other users fill in, such as names or ticket descriptions.
  2. List every tool the model can call and write down, for each one, which user roles may trigger it and with which arguments.
  3. Plant canary values: a fake API key in a test system prompt, a marker string in a document only an admin can see, a unique token in another test user's record. Any output that contains a canary is a failure, whatever the surrounding text says.
  4. Write direct attacks for each failure type: requests to ignore previous instructions, role-play framing, instructions split across several turns, encoded text, and the same attack in the other languages your users write in.
  5. Write indirect attacks by putting poisoned content into a test copy of each channel: a document in the test index, a ticket body, a page the agent might browse, and an image with text in it if the model accepts images.
  6. Add benign look-alikes, such as a real user asking how prompt injection works, so you also catch a filter that blocks legitimate questions.
  7. Keep the suite in version control next to the prompts, and add a case every time a real attempt shows up in your logs.

Indirect injection deserves extra weight in any system with retrieval. If anyone outside your team can get a document into the index, treat that document as untrusted input, the same as a message typed into the chat box. We cover the retrieval side of this in RAG anti-patterns we keep finding in production.

Run it in CI on every prompt or model change

An injection suite run once before launch goes stale quickly, because the changes that alter your exposure are routine edits. Run it automatically whenever any of these change:

  • the system prompt or any prompt template
  • the model, the model version or the provider
  • a tool definition, a new tool, or a change to tool permissions
  • a new retrieval source, or a change to how retrieved text is inserted into the prompt
  • the output renderer, for example turning on markdown, links or images

Model output varies between runs, so one clean pass proves little. Run each attack case several times and treat a single success as a failure. Block the release on any canary leak or unauthorised tool call, and review the softer cases by hand. This is the same release discipline as eval-first SI delivery, with attacks in place of ordinary test questions.

Limit what the tools can do

Testing tells you where you stand. Architecture decides how bad a successful injection can be. These controls matter more than any input filter, because they still hold when the model is fooled.

  • Enforce authorisation in application code, not in the prompt. The model proposes an action; your code checks the real user's permissions before it runs.
  • Give each tool the narrowest scope that works: read-only where possible, credentials tied to the current user, and no access to records that user could not open directly.
  • Require human approval for actions that are irreversible or move money, using the patterns in human-in-the-loop approval for SI agents.
  • Do not render external images from model output, and restrict links to an allowlist of your own domains. A strict Content Security Policy on the chat page adds a second layer.
  • Mark retrieved and third-party content clearly as data in the prompt, separate from instructions. This reduces the risk; it does not remove it.
  • Keep secrets, keys and permission rules out of the prompt entirely.

Each restriction costs some convenience, and that trade-off is real. An agent that cannot browse freely or send email without approval looks less impressive in a demo. But if a feature does not need a tool, the simplest and strongest defence is not to give it one.

A short checklist before launch

  • Every input channel and every tool is listed, with the roles allowed to use each tool.
  • Canary secrets are planted, and the suite fails on any leak.
  • Direct and indirect attacks exist for each of the four failure types.
  • Assertions check tool calls, arguments and rendered URLs, not refusal wording.
  • The suite runs in CI on every prompt, model, tool or renderer change.
  • Authorisation is enforced outside the model, and risky actions need human approval.

If your launch is close and the only injection testing so far is a few attempts in a chat window, this list is the place to start. Our SI-driven QA team builds injection suites and wires them into release pipelines, and Octalcode can review an agent's tool permissions before it goes live.

Available for new engagements

Have a production SI problem to solve?

30 minutes, one of our seniors, no slide deck. By the end of the call you will know whether we are the right team, and if not, who is.

Or call +1 (512) 710-5701

Let's scope it.Instant answers · free project scoping