Sanitizing Input
Input handling is one of the most important security habits in JavaScript.
Every value that enters your app should be treated as untrusted until it has been checked.
Untrusted input can come from:
- forms
- query strings
- route parameters
- request bodies
- browser storage
- API responses
- uploaded files
- third-party widgets
Validation vs Sanitization
Validation asks: "Is this value acceptable?"
Sanitization asks: "Can this value be cleaned into a safer form?"
They are related, but they are not the same.
Validation Example
Validation rejects values that do not match your rules.
function isValidUsername(username) {
return /^[a-z0-9_]{3,20}$/i.test(username);
}
console.log(isValidUsername("alex_21")); // true
console.log(isValidUsername("a")); // false
console.log(isValidUsername("alex admin")); // falseThis function defines what a username is allowed to be.
It does not try to clean every possible input.
It accepts or rejects.
Sanitization Example
Sanitization transforms a value.
function normalizeEmail(email) {
return email.trim().toLowerCase();
}
const email = normalizeEmail(" ASHA@example.COM ");
console.log(email); // asha@example.comThis is useful for consistent storage and comparison.
But sanitization should not replace validation.
After normalizing, still validate the result.
function isLikelyEmail(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
const email = normalizeEmail(input.value);
if (!isLikelyEmail(email)) {
showError("Enter a valid email address.");
}Prefer Allow Lists
An allow list defines what is allowed.
const allowedSortFields = new Set(["name", "price", "createdAt"]);
function getSortField(value) {
if (allowedSortFields.has(value)) {
return value;
}
return "createdAt";
}This is usually safer than trying to list every bad value.
Bad-value lists are easy to miss.
Good-value lists are easier to reason about.
Validate on the Server
Frontend validation improves user experience.
It does not protect the server by itself.
Users can change browser code, disable JavaScript, edit requests, or call your API directly.
Always validate important rules on the server too.
Frontend validation is helpful for:
- quick feedback
- fewer accidental bad requests
- better form messages
Server validation is required for:
- authorization
- payment amounts
- account ownership
- roles and permissions
- database writes
Validate Data from APIs
Do not assume an API response has the exact shape you expected.
function parseUser(data) {
if (
typeof data !== "object" ||
data === null ||
typeof data.id !== "string" ||
typeof data.name !== "string"
) {
throw new Error("Invalid user response");
}
return {
id: data.id,
name: data.name,
};
}This kind of checking protects your UI from broken or unexpected data.
In larger apps, teams often use validation libraries to define schemas.
Encode Values for URLs
When building URLs, use the platform APIs.
const params = new URLSearchParams({
search: searchInput.value,
page: "1",
});
const response = await fetch(`/api/products?${params.toString()}`);URLSearchParams handles URL encoding.
Avoid manually joining query strings with raw user input.
Do Not Trust Hidden Inputs
Hidden form inputs are still user-controlled.
<input type="hidden" name="role" value="user">A browser user can edit this value before submitting.
Never rely on hidden inputs for permissions, prices, user IDs, or ownership checks.
The server should decide those values from trusted data.
Common Mistakes
Do not only validate in the browser.
Do not confuse trimming a value with making it safe everywhere.
Do not use one sanitizer for every output context.
Do not accept unexpected object properties without thinking about how they are used.
Do not rely on hidden fields for security decisions.
Summary
Validation decides whether input is acceptable.
Sanitization cleans or normalizes input.
Use allow lists, validate important rules on the server, and use built-in APIs like URLSearchParams for encoding.