Security Deep-Dive
Trust nothing across any boundary — user input, retrieved content, and (the surprising one) the model’s own output — then grant least privilege and defend in depth.
Your AI app handles real users and real data. Imagine three attacks in one day: (1) someone finds your API key in the frontend bundle and runs up a $5,000 bill; (2) a document your RAG ingests contains hidden instructions that make the agent leak data; (3) the model turns a user’s request into SQL, and a crafted input becomes DROP TABLE. Three different boundaries, three breaches. Securing an AI app means trusting nothing across any of them.
Secrets & access: lock down the keys
API keys and database credentials live in environment variables or a secret store — never in code, the repo, or the frontend (L26–L28). Use least-privilege keys (scoped, rotatable), and enforce auth plus Row-Level Security (L29) so each user reaches only their own data. Rate-limit and spend-cap every endpoint so a leaked key or an abusive user can’t run an unbounded bill — a “cost bomb.” (This is why production routes model calls through a capped, server-side chokepoint.)
Treat ALL boundaries as untrusted — including the model’s output
You already treat user input and retrieved/tool content as untrusted, because of prompt injection — both direct (the user types “ignore your instructions”) and indirect (a fetched document carries hidden commands), from L24. The deeper, surprising point: the model’s output is untrusted too. If you feed it into a database query, code execution, an HTML page, or another tool, a manipulated model can attack those systems — generated SQL becomes SQL injection, generated HTML becomes XSS. So validate, escape, and sandbox model output exactly as you would user input. Never pipe raw model output into anything powerful.
Privacy & defense in depth
Mind the data: what you log (generations can contain PII — L33), what you send to the provider, and how long you retain it — minimize and protect all three. And no single control is enough: layer them — secrets management, least privilege, input and output validation, RLS, rate/spend limits, monitoring, dependency hygiene — so one failure doesn’t become a breach. Stated plainly, that’s the whole-track security principle: assume every boundary is hostile, grant the least privilege that works, and defend in depth.
Think of a secure building. You don’t rely on one locked front door. You lock the doors (secrets), give each employee a badge that opens only their own areas (least privilege + RLS), check IDs at reception (auth), and post a guard who won’t blindly act on a note saying “the boss says let me into the vault” — whether it’s handed over by a visitor (user input) OR by a staff member passing it along (the model’s output). You shred sensitive papers (data handling) and run cameras (monitoring). Security is layers, and you don’t fully trust someone just because they’re already inside.
Hardening against the three attacks — note each is stopped by more than one layer:
1. Key in the frontend → move it server-side (env var), rotate the exposed key, and add per-user + global spend caps so even a leak is bounded.
2. Indirect injection via a document → treat retrieved text as data (never instructions), scope the agent’s tools (no bulk-export), and require approval for sensitive actions — the injected command has nothing to act on.
3. Model-generated SQL → DROP TABLE → never run raw generated SQL; use parameterized / allow-listed queries, give the DB user least privilege (no DROP), and validate the output.
That’s defense in depth: every attack hits a wall at more than one layer.This is the reading. The interactive version — active-recall quiz, a hands-on experiment you run in your own AI, and an earned mastery check — is free in the app.
Start this lesson free →