Stop 13 · SecurityTopics · 7/12

Input Validation & Sanitization

Part of the Backend Developer Roadmap

In short

Every field in a request body is a stranger's opinion. Validate it at the door, and the rest of your code gets to work with clean, predictable data.

Rejecting or cleaning malformed, unexpected, or malicious input before it reaches your business logic or database — the single most effective general-purpose security practice.

The blob at a railway luggage scanner pulls out a bag holding a spiky object.

Think of it like this

The station luggage scanner

At a big railway station, every bag rolls through the scanner before it reaches the platform. Most are fine. The odd one with something dangerous is pulled out right there, not on the train. Validation is that scanner for your API.

Watch it happen

A signup request through the checks

Raw body
Parse JSON
Validate
Normalise
Handler

1/5The body arrives: { "email": " Riya@Mail.com ", "age": "19", "role": "admin" }.

The big ideas

What you need to know

Validate on the server

Frontend checks are for user comfort. Attackers skip your form and send raw requests, so the server must check again.

Allowlist, not blocklist

Describe what good input looks like: type, length, format. Reject everything else instead of chasing bad patterns.

Sanitise means clean up

Trim spaces, normalise case, strip unknown fields and unsafe HTML. It makes data consistent, not magically safe.

One schema, many uses

A Zod schema gives runtime checks and TypeScript types together, so your types can't drift from your checks.

See it in code

Walk through the code

ts
1import { z } from "zod";2 3const SignupSchema = z.object({4  email: z.email(),5  age: z.number().int().min(16).max(100),6  name: z.string().trim().min(1).max(50),7});8 9app.post("/signup", (req, res) => {10  const result = SignupSchema.safeParse(req.body);11  if (!result.success) return res.status(400).json(result.error.issues);12  createUser(result.data); // only clean, typed data gets here13  res.status(201).end();14});

1/3The schema describes good input: a real email, a whole-number age in range, and a trimmed name of sane length.

z.object strips keys you didn't declare, so a sneaky "role": "admin" never reaches createUser. That alone blocks a whole class of mass-assignment bugs.

Save yourself the pain

Common mistakes

Oops

Passing req.body straight into db.user.create().

Do this instead

Pick fields through a schema first. Otherwise a user can set isAdmin or balance just by adding it to the JSON.

Oops

Trusting that the React form already validated it.

Do this instead

Run the same rules on the server. Share the Zod schema between both if you like.

Your mission

Put a scanner on one endpoint

~30 min

Quick check

Why is z.object useful against mass-assignment attacks?

Go deeper

  1. 1Add strict validation (type, length, format) to every field of a public endpoint.
  2. 2Reject unexpected extra fields in a request body rather than silently ignoring them.
  3. 3Validate on the server even if the client also validates — never trust the client.

More topics at this stop

Stuck on this topic? Ask an Insider

Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.

Download
InsideEdge