Hostile support tickets with hidden commands
A bot that summarises and routes hostile tickets safely instead of acting on instructions hidden inside them.
Defend what you build against prompt injection and abuse
The chapter for people who ship AI, not just use it: privacy keeps your own secrets out of a chatbot, security defends a system you build against an attacker who feeds it hostile input. Taught as vulnerable → hardened pairs across the real threat model — prompt injection (direct and indirect), untrusted output, over-powered tools, and supply chain — mapped to the OWASP Top 10 for LLM Apps (2025).
In this chapter you will learn how to build AI applications that resist prompt injection and other forms of abuse by separating commands from untrusted data, enforcing strict access controls, and requiring human approval for high‑impact actions. You will be able to implement safe bots, audit trails, adversarial testing, and content sanitisation measures that keep credentials hidden, limit tool privileges, and treat all model input and output as potentially malicious. The techniques also cover supply‑chain verification, guard‑model screening, and layered defenses so that any injection is contained, detected, and blocked before it can cause damage.
Prompt injection is when an attacker feeds hostile input that manipulates the AI’s instructions, causing it to behave contrary to your intended logic or reveal protected data.
You must validate and sanitize any content generated by the model before using it downstream, ensuring it cannot be exploited to trigger unsafe actions or leak information.
A compromised component in your AI stack—such as a poisoned model or library—can introduce hidden vulnerabilities that attackers exploit, so you need to verify the integrity of every piece you integrate.
Four layers of defense: separate instructions from input, screen retrieved content, guard with a classifier, harden the prompt
Concatenate the user message (or a retrieved document) straight into the system prompt as one big string, so instructions and untrusted content sit side by side.
Keep YOUR instructions in the system prompt. Deliver third-party content only inside clearly-labelled, encoded data blocks (e.g. wrapped in tags or a delimited field) that the prompt explicitly frames as data to process, not commands to obey.
Let a RAG app or agent obey instructions it finds inside a fetched web page, email, or PDF — because that text arrived through your own retrieval step, you trust it.
Declare tool output, retrieved documents, and search results as untrusted data to REPORT, not commands to follow. Screen what a tool returns before the agent acts on it; never let fetched content silently change the plan.
Pass raw user input straight to the model and stream the raw output straight back to the user, with nothing watching either side.
Pre-screen input with a small classifier for known injection patterns and obviously hostile requests; monitor outputs for leaked system prompts or exfiltrated data before they are shown. Block or flag what the screen catches.
Rely on a one-line "be helpful and answer the user" system prompt, with no stated boundaries and no limit on how many times someone can probe it.
State explicit boundaries and a clear refusal script in the system prompt, and rate-limit or ban repeat offenders who keep probing. Treat this as friction that raises the bar — never as the thing that holds the secret.
Don't trust model output, don't over-empower tools
Put an API key, a database password, or a rule like "only admins may delete records" directly in the system prompt and trust the model to keep it.
Remove all credentials from prompts — load them server-side from a secret store the model never sees. Enforce authorization (who may do what) in deterministic code OUTSIDE the model, so a leaked prompt reveals nothing and bypasses nothing.
Render the model output directly as HTML, eval() the code it returns, or interpolate it straight into a SQL query or shell command.
Context-aware encode every output: HTML-escape before rendering, use parameterized queries for SQL, apply a strict Content-Security-Policy, and schema-validate structured output before any downstream system consumes it.
Hand the agent an open-ended shell tool and broad admin credentials so it "can do whatever the task needs."
Expose only granular, purpose-built tools, each with the minimum scope to do its one job (e.g. "look up an order by id", not "run SQL"). Scope the credentials per task so a tool can touch only what it must.
Let the agent send money, delete records, or email customers fully autonomously, with no human in the loop.
Require explicit human approval — with a preview of exactly what will happen — for irreversible or high-impact actions (payments, deletions, outbound email). Rate-limit the lower-impact actions you do automate.
Trust your ingredients, watch the system, attack it yourself
Wire in a random fine-tune, LoRA adapter, or MCP server you found from an unverified source because it looked convenient.
Use trusted registries; verify provenance with hashes or signatures before you load anything; keep a signed SBOM (software bill of materials) of every model, adapter, and plugin; and patch dependencies on a schedule.
Ship once, assume the system prompt holds, and add no monitoring or adversarial testing.
Stack defenses: input/output classifiers + filters + human-in-the-loop on risky actions + logging of every tool call. Then red-team your OWN workflow with planted injections before launch, and keep monitoring in production.
A bot that receives support tickets, extracts the content, and returns a safe summary without executing any hidden commands.
Create a ticket summariser that treats incoming text as untrusted data
The SentinelOne AI firewall is a real‑time filter that scrubs incoming prompts and model outputs for injection attacks.
You will have enabled automatic blocking of adversarial prompts in your AI app.
A logging layer that records each call a bot makes to external tools, including arguments and user context, and raises an alert when a call deviates from normal patterns.
Trace every tool usage and receive early warnings of suspicious activity
SentinelOne Agentic AI Security provides searchable logs of every agent action, including tool invocations.
You will generate a log that automatically highlights tool calls that deviate from normal patterns.
A short adversarial testing suite that injects crafted prompts into your bot and verifies that the system safely contains them.
An automated checklist validates all injection cases before shipping the AI application
SentinelOne’s AI Application Security can automatically test an app for prompt injection, jailbreaks, and data poisoning before it goes live.
You will execute a built‑in test suite that validates your app is resistant to common injection attacks.
GitHub Advanced Security’s secret protection feature scans code repositories for exposed credentials and other secrets.
You will configure secret scanning so that any committed secret triggers an alert and is blocked from merging.
API_KEY=12345) and push it; verify GitHub creates an alert and prevents merging.26 outcomes in all — one per recipe below.
Hostile support tickets with hidden commands
A bot that summarises and routes hostile tickets safely instead of acting on instructions hidden inside them.
Bot can’t change anything on its own
Even if the bot is talked into something, its tools simply cannot issue refunds or change accounts without a human.
Hidden instructions in KB articles get ignored
Indirect injections hidden in your own knowledge base are caught before the agent follows them.
Hidden instructions in employee messages
The bot answers from policy safely, even when an employee's message hides an instruction.
Ops agent runs destructive actions on its own
The agent can investigate freely, but every destructive action needs a human to confirm exactly what will happen.
Unsure what actions my AI takes
A replayable audit trail and an early warning when the agent does something out of pattern.
Want to catch prompt injections before launch
A short, repeatable adversarial pass that finds the gaps before a real attacker does.
API keys showing up in chatbot prompts
A prompt-leak jailbreak exposes your instructions but none of your credentials.
Potential input hijacks before release
A go/no-go security gate that catches an obvious hijack before customers (or attackers) do.
Admin rules can be bypassed by prompts
Permissions hold no matter what the model is persuaded to say, because the model never makes the call.
Need to keep deal docs out of public AI tools
Confidential deal information is processed only inside a controlled environment, and you have a record of which tool you used and why it met the bar.
Payments could run automatically
No payment ever leaves automatically; a person confirms exactly what is about to happen.
AI can suggest overspending
Limits and approvals hold even when the model is persuaded otherwise, because it never enforces them itself.
Employees can’t pull salary info
Sensitive records stay gated by real authorization that the model cannot be argued past.
When a résumé tries to mess with other candidates
A poisoned résumé can only affect its own evaluation, never reach across to other candidates' data.
Recruiting while protecting candidate privacy
Candidate data is processed under a controlled arrangement, and your recruiting workflow handles that personal data responsibly from intake to archive.
AI just flags candidates
A recruiter reviews every shortlist decision; AI speeds up screening without replacing human judgment at the gate. Every fact in a candidate brief is source-confirmed.
Never paste patient identifiers into public AI chatbots
A bright-line guardrail staff can follow without judgment calls in the moment, closing the most common accidental-leak path — pasting a real patient case into a general AI tool.
Need a GDPR‑compliant rollout plan for a clinical AI tool
A clinical assistant that can be deployed under GDPR/data-protection obligations with a defensible paper trail, rather than one bolted on ad hoc after an incident.
Adversarial PDF tries to give new instructions
A research RAG that reads adversarial papers as content to summarise, never as commands to follow.
I can’t tell if a model is safe
You only run models whose origin you verified, with a record of exactly what you shipped.
Hidden instructions in search results
The agent reports what it found rather than blindly obeying instructions hidden in a search result.
Need each memo number traced back to its source
Every metric in your investment memos and IC materials has a traceable, human-confirmed source — and the AI is used to draft and structure, never to originate numbers.
AI‑generated text contains <script> tags
AI content renders as text, not as executable markup — closing a stored-XSS hole.
Injected markup can run scripts in my AI chat widget
A second layer behind output-escaping: the browser itself blocks injected script execution.
AI output that doesn’t match the expected shape is blocked
Only well-formed, expected output ever reaches the system that consumes it.
Invoice has hidden approve and pay command
The extractor reads hostile invoices safely instead of acting on text planted inside them.
Incoming emails may hide malicious commands
Inbound emails are summarised and drafted from safely, never obeyed as commands.
Need agents to touch only one CRM record each
A compromised sales agent can touch one record at a time, never dump or wipe the database.
Unsure if AI‑generated emails are safe
Nothing leaves your domain without a person seeing exactly what will be sent and to whom.
Payments or deletions run automatically
A confirmation step turns a successful breach into a blocked prompt. For anything irreversible or high-impact, the model proposes and a human approves. Even if an injection slips through every earlier layer, a mandatory human approval on the dangerous action stops it cold: the breach becomes a suspicious prompt a person declines, not a wire transfer (OWASP LLM06).
Giving an AI a generic admin shell
A successful injection can only do what your tools allow. Expose narrow, purpose-built tools with the minimum scope — not an open-ended shell with broad admin rights. You cannot guarantee an injection never lands, but you CAN bound the blast radius: with least-privilege tools, the worst a successful injection achieves is whatever those narrow tools permit — and nothing more (OWASP LLM06).
Model output could be malicious
Model output is just a string an attacker may have influenced. Encode and validate it the same way you would any user input before it touches HTML, SQL, a shell, or another service. Unsanitized model output is an injection vector into your OTHER systems — it becomes XSS, SQL injection, SSRF, or remote code execution exactly as untrusted user input would. Encode it at every boundary (OWASP LLM05).
Putting API keys or admin rules in prompts
A prompt can leak, and it cannot be trusted to enforce a rule. Credentials belong in a secret store; authorization belongs in deterministic code outside the model. A system prompt can be leaked by a clever jailbreak, and a model can be talked past a "rule" written in prose. Secrets and access checks must live where neither leaking nor persuading the model can reach them (OWASP LLM07 / LLM02).
User prompts go straight to the model
A cheap, separate classifier in front of (and behind) your main model catches the obvious attacks before they reach it — and catches leaks before they reach the user. A small dedicated screen is cheap to run and catches the casual, high-volume attacks — freeing your main model and your team to focus on the subtler ones. It is one layer, not the whole defense (OWASP LLM01).
A plain ‘be helpful’ prompt gets probed
A bare "be helpful" prompt invites probing. Named boundaries plus a refusal script and rate-limits resist casual jailbreaks — but the prompt is never the last line of defense. Explicit, named boundaries plus rate-limits make casual jailbreaks far harder, but a determined attacker can still talk a model around its prompt — so this layer buys friction, not a guarantee (OWASP LLM01).
Content fetched from webpages or PDFs may hide attacks
The dangerous payload is rarely typed by your user — it is planted in a page, email, or PDF your system fetches and reads. Treat everything a tool returns as untrusted. Indirect injection is the attack that scales: the adversary plants the payload in content your system reads on its own, so they never need access to your prompt. Labelling retrieved content as data is the core mitigation (OWASP LLM01).
Instructions and user input run together
The model cannot tell a command from data when they are mixed into one blob. Keep your rules in the system prompt and deliver everyone else's text as clearly-labelled, encoded data. When commands and data are concatenated, the model has no reliable way to tell which is which — and an attacker phrases their data as a command. A clear boundary is the foundation every other defense builds on (OWASP LLM01).
Prompt injection gets through one guardrail
No single layer holds. Assume injection eventually succeeds, build defense-in-depth, log every tool call, and attack your own workflow before an outsider does. Every individual layer can be bypassed, so the goal is containment and detection, not a perfect wall: assume an injection will land, make sure it cannot do much, and make sure you SEE it when it does (Google Security; OWASP LLM01).
Using an unverified model or adapter
An untrusted model, adapter, or plugin can be backdoored. Trust your ingredients: use known registries, verify provenance, and keep a signed inventory of what you ship. A model or plugin from an unverified source can carry a hidden backdoor or poisoned behaviour that no prompt-level defense will catch. Provenance and a signed inventory are how you trust what you actually shipped (OWASP LLM03 / LLM04).
The same set on /recipes, filtered by tool and role.
A clear tour of the OWASP Top 10 risk map this chapter follows — the threats you are defending against, explained for builders.
The headline risk explained from first principles — direct vs indirect injection and why mixing instructions with untrusted data is the root cause.
Defensive patterns for agents specifically — guarding against payloads hidden in retrieved content, with least privilege and screening.
Different threat, different side of the table. The Privacy chapter is about you as a USER keeping your own secrets out of a chatbot you type into. This chapter is about you as a BUILDER defending an AI system you ship against an attacker who feeds it hostile input — prompt injection and the rest. Privacy protects your data going in; security protects your application against text designed to subvert it.
Prompt injection is when untrusted text is interpreted as instructions and hijacks what your model does. DIRECT injection is the user typing the hostile instruction themselves. INDIRECT injection is more dangerous: the attacker plants the instruction inside content your system later reads on its own — a web page, an email, a PDF, a document in your RAG index — so it executes without the attacker ever touching your prompt. The core defense for both is to keep your instructions separate and treat all third-party content as data, not commands.
Declare retrieved documents, tool output, and search results as untrusted DATA to report on, never as commands to follow — keep your real instructions in the system prompt, clearly separated. Screen what a tool or retrieval step returns before the agent acts on it, and use guardrails (a classifier in front of the model, output monitoring behind it) plus least-privilege tools so that even a payload that slips through cannot do much. Assume some will get through and contain the impact.
No. A system prompt can be leaked by a determined jailbreak, and a rule written in prose can be talked past — so the prompt is the wrong place for anything that must hold. Keep credentials out of the prompt entirely (load them server-side from a secret store) and enforce authorization in deterministic code outside the model. Then a leaked prompt reveals no secret and bypasses no check.
Because model output is just a string an attacker may have shaped — and if you render it as HTML, eval() it, or interpolate it into SQL or a shell command, that string becomes XSS, SQL injection, SSRF, or remote code execution in your OTHER systems. The fix is to treat output exactly like untrusted user input: context-aware encode it (HTML-escape, parameterized queries), apply a strict CSP, and schema-validate structured output before anything downstream consumes it.
As little as the job needs. Expose granular, purpose-built tools each scoped to one task, rather than an open-ended shell with broad admin credentials — and require human approval (with a preview) for irreversible or high-impact actions like payments and deletions. Least privilege bounds the blast radius: even a successful injection can only do what your narrow tools permit, and the dangerous actions still need a human to say yes.
You need layers. No single mitigation is reliable on its own — a determined attacker eventually finds the gap — so the goal is defense-in-depth aimed at containment and detection: input/output classifiers, content filters, least-privilege tools, human-in-the-loop on risky actions, and logging of every tool call, combined with red-teaming your own workflow. Assume an injection will eventually land, make sure it cannot do much, and make sure you see it when it does.
No. An untrusted model, fine-tune, adapter, or plugin/MCP server can be backdoored or carry poisoned behaviour that no prompt-level defense will catch. Use trusted registries, verify provenance with hashes or signatures before loading anything, keep a signed SBOM of every model and plugin you ship, and patch dependencies. Trust your ingredients the same way you trust the rest of your supply chain.
Indirect prompt injectionJailbreakSystem-prompt leakageData / model poisoningImproper output handlingExcessive agencyTrust boundaryGuardrailLeast privilegeHuman-in-the-loop (HITL)Red-teamingAsk, share, or report — over on the Heidelberg AI community forum.