Chapter 1 · Practice 1 of 4
Know every place untrusted data enters your code
Why it matters
You cannot validate input you did not notice. Most teams think of form fields and JSON bodies, but attackers control far more than that. Treat all of these as untrusted:
| Source | Easy to forget because |
|---|---|
| Query strings, path segments, request bodies | obvious, but often only checked in the browser |
Headers: Host, X-Forwarded-For, Referer, User-Agent | they look like infrastructure, not user data |
| Cookies | the client can set any value it likes |
| Uploaded files and their names | the name, the type and the bytes are all chosen by the sender |
| Webhooks and partner APIs | they come from "trusted" companies, over the internet |
| Rows written earlier by users | stored data becomes input again when you read it |
| Message queues and caches | other services may have been fed by users |
| Output from a language model | it can be steered by any text the model read |
A trust boundary is any line where data moves from something you do not control into something you do. Draw them for each service: the HTTP edge, the queue consumer, the cron job that reads an S3 bucket. Every boundary needs validation on the inside, and every interpreter after it (SQL, shell, HTML, file system) needs its own safe API.
Do
- List the trust boundaries of each service in its README or threat model
- Treat headers, cookies and stored user content as input
- Validate webhook payloads after verifying their signature
Avoid
- Trusting a value because an internal service sent it
- Relying on browser validation or disabled form fields
- Using X-Forwarded-For from clients you do not proxy