Skip to content
ML Academy

LLMs, GenAI, RAG, agents, evaluation · insight-1701

Never let user text become the template, and render each prompt exactly once

Evidence type
practitioner heuristic
Difficulty
easy
Roles
ML engineer, Applied AI
Industries
cross-industry

Summary: situation, action, reason, boundary

  1. Situation

    A prompt is built by pasting a customer message into a template string and then passing the result through a second formatting call.

  2. Action

    Treat the template as code and the message as a variable value. Render once, with user text supplied only as a value. Pass only plain strings and numbers in the render context, not whole objects, and add a test whose message contains braces and dotted field names.

  3. Reason

    Python's format syntax lets a field name be followed by attribute and index lookups, so an object in the context can be read through text. Jinja's own documentation says its sandbox alone is not perfect security, which is why the context is kept small.

  4. Boundary

    Any prompt assembled with str.format, f-strings followed by a template engine, or an editable template store.

Symptom or risk

Braces in the message are read as placeholders: the call fails with a missing-key error, or a field such as a customer record attribute is expanded into the prompt, where the model can repeat it.

Exceptions

Templates written and reviewed only by your team, rendered once, with no user text in the template body.

Trade-offs

Flat string contexts need extra assembly code and a prompt-building layer.

Pitfalls

Appending user text before the final render, or trusting delimiters around the text to stop template syntax from being evaluated.

Example

Hypothetical: the complaint text is concatenated into a template and the result is formatted again with a customer object in the context. A complaint containing the text {customer.email} comes back with the address filled in; a complaint containing {braces} raises a KeyError. Both were reproduced in Python.

Lessons and concepts

Claims and their sources

  • The Python documentation's format string syntax allows a field name to be followed by attribute lookups (resolved with getattr) and index lookups, as in {0.weight} and {players[0]}; the page carries no warning about untrusted format strings, so the risk statement is the course's inference.

    Python documentation: string, Format String Syntax

  • The Jinja documentation says its sandbox intercepts attribute access, method calls and string formatting but is not by itself a solution for perfect security, and advises passing only the data needed.

    Jinja documentation: Sandbox