How to Secure useSearchParams in React
The useSearchParams hook in React is a powerful tool for
reading and modifying the query string in the URL. However, because
query parameters are user-controlled inputs, they can expose your
application to security vulnerabilities like Cross-Site Scripting (XSS),
open redirects, and prototype pollution. This article provides a
straightforward guide on how to secure the useSearchParams
hook in React by validating inputs, sanitizing data, and safely handling
application state.
1. Validate Query Parameters with Schemas
Because URL parameters are always strings, they must be validated and parsed into the correct data types. Using a schema validation library like Zod ensures that only expected values are processed by your application, mitigating type injection attacks.
import { useSearchParams } from 'react-router-dom';
import { z } from 'zod';
// Define a strict schema for search parameters
const searchSchema = z.object({
page: z.coerce.number().int().positive().default(1),
search: z.string().max(100).optional().default(''),
});
export function SecureComponent() {
const [searchParams] = useSearchParams();
// Convert URLSearchParams to a plain object
const paramsObject = Object.fromEntries(searchParams.entries());
// Safely parse the object against the schema
const result = searchSchema.safeParse(paramsObject);
if (!result.success) {
// Fallback or handle validation error
return <div>Invalid query parameters.</div>;
}
const { page, search } = result.data;
return (
<div>
<p>Page: {page}</p>
<p>Search Query: {search}</p>
</div>
);
}2. Prevent Cross-Site Scripting (XSS)
Never directly render raw values from useSearchParams
into dangerous HTML attributes (such as href or
src) or pass them directly to
dangerouslySetInnerHTML.
If your application reads a URL from query parameters to dynamically
generate a link, validate the protocol to prevent
javascript: payload execution:
const redirectUrl = searchParams.get('continueTo');
const getSafeUrl = (url) => {
if (!url) return '/';
try {
const parsed = new URL(url, window.location.origin);
// Allow only HTTP and HTTPS protocols to prevent javascript: schemes
if (parsed.protocol === 'http:' || parsed.protocol === 'https:') {
return parsed.toString();
}
} catch {
// Handle relative paths safely
if (url.startsWith('/') && !url.startsWith('//')) {
return url;
}
}
return '/';
};
// Usage
<a href={getSafeUrl(redirectUrl)}>Continue</a>3. Mitigate Open Redirect Vulnerabilities
If you use useSearchParams to retrieve a redirect path
after an action (e.g., ?next=/profile), malicious actors
can modify this parameter to redirect users to phishing sites.
To prevent open redirects: * Enforce relative paths:
Ensure the target path starts with a single / and does not
start with // or a protocol. * Use an
allowlist: Only redirect to a predefined set of internal domain
routes.
const nextPath = searchParams.get('next');
const safeRedirect = (path) => {
const isRelative = path && path.startsWith('/') && !path.startsWith('//');
return isRelative ? path : '/dashboard';
};4. Limit Parameter Size to Prevent DoS
Large, deeply nested, or repetitive query strings can crash client-side parsing logic or trigger server-side errors. Restrict the maximum character length of the query string before processing it.
const rawQueryString = searchParams.toString();
if (rawQueryString.length > 2048) {
throw new Error("URL query parameters exceed maximum safe length limit.");
}