Best Practices for Building LLM Apps

Chapter 3 · Practice 2 of 5

Enforce permissions in code, not in the system prompt

From Prompt injection and the OWASP LLM Top 10

Why it matters

"Only answer about the current user's orders" in a prompt is a request, not a control. The model can be talked out of it.

Put access checks in the tools and queries the model calls. The order lookup tool should only ever return orders for the authenticated user id, which your code passes in, not the model. The model may choose which order to look at; your code decides whose orders exist.

For every tool, ask one question:

Example

TypeScript
// The model chooses the order; your code decides whose orders exist
async function getOrder({ orderId }: { orderId: string }, ctx: { userId: string }) {
  return db.order.findFirst({ where: { id: orderId, userId: ctx.userId } });
}