← Shipping AI apps · Chapter 1

Prompt injection: keep untrusted content inside data boundaries

Recognize indirect instructions in documents and tool results and enforce permissions in application code.

After this guide, you can

Separate content from authorization and build allowlists outside the model's prompt.

Prompt injection occurs when untrusted content attempts to change system behavior. It may enter through a user message, retrieved document, webpage, text extracted from an image, or tool result.

Telling a model to resist attacks is not a stable security boundary. The important questions are what external content can influence and what the application lets it trigger.

Separate content from authorization

A document can supply evidence, but a sentence asking for an administrator tool does not grant execution permission. A credible source also does not make every sentence in it an instruction for your system.

OWASP's prompt-injection guidance notes that RAG and fine-tuning do not fully address the risk. Retain source and trust information when connecting external material to a model.

Tool permissions, user identity, and allowed resources come from trusted application logic, not from a model's summary of a document.

Constrain capability instead of guessing every attack

Choosing a registered resource identifier is often easier to control than accepting an arbitrary URL. Actual network access also needs rules for redirects, DNS resolution, and private addresses; a URL string check alone is insufficient.

Writes need separate authorization. Keep credentials inside the executor and return only the data needed for the task instead of placing tokens in model context.

Bound result size, tool count, and elapsed time. Misleading content should not give a task unlimited resources.

Practice with a resource allowlist

This offline example makes no network request. The model can propose a resource identifier; the application reads from registered material. Both the resource mapping and permission set come from trusted code.

resources = {"public-guide": "A short public engineering guide."}

def read_document(arguments, granted_resources):
    if not isinstance(arguments, dict) or set(arguments) != {"resource_id"}:
        raise ValueError("invalid arguments")
    resource_id = arguments["resource_id"]
    if not isinstance(resource_id, str):
        raise ValueError("resource identifier required")
    if resource_id not in granted_resources or resource_id not in resources:
        raise PermissionError("resource not authorized")
    return resources[resource_id]

assert read_document({"resource_id": "public-guide"}, {"public-guide"})
try:
    read_document({"resource_id": "private-config"}, {"public-guide"})
except PermissionError:
    print("Unauthorized resource rejected")
else:
    raise AssertionError("unauthorized access accepted")

The allowlist does not detect every injection. Its value is limiting the resources a misled model can request to those explicitly authorized by the application.

Test refusals and unusual paths

Construct documents containing indirect instructions to use unauthorized tools, access additional resources, or hide execution. Check that the executor still applies the original permission rules.

Inspect caches and cross-task state so one task's permissions do not leak into another. Preserve the external-data status of tool results when they enter the next model context.

After finding an attack, check whether the capability boundary was too broad before adding prompt wording and detection. Keyword filters can be a supporting layer but are not authorization.

Try it next

List the resources your application can read and modify and define allowed scope for each capability. Use a constructed request for extra material to check that application code rejects it.

Define states for denied permission, uncertain results, and required confirmation. The next guide measures task time and resource use without unnecessarily recording sensitive content.

Sources & further reading

Sources checked on 2026-11-10. Original engineering explanation; examples are teaching data, not production measurements.