REDOS in search filter
Description
In FinalityProviderState.tsx, the search filter creates a regular expression out of the user's input and uses that to filter finality providers.
This is an anti-pattern since it could lead to regular expression denial of service (REDOS).
const FILTERS = {
search: (fp: FinalityProvider, filter: FilterState) => {
const pattern = new RegExp(filter.search, "i");
return (
pattern.test(fp.description?.moniker ?? "") || pattern.test(fp.btcPk)
);
},
// ...
};
This filter can be set via a URL query parameter or by the user directly:
export function FinalityProviderState({ children }: PropsWithChildren) {
const searchParams = useSearchParams();
const fpParam = searchParams.get("fp");
const [filter, setFilter] = useState<FilterState>({
search: fpParam || "",
status: "active",
});
// ...
}
Impact
The impact of this issue is limited since the regular expression only runs on the client. An attacker could provide a malicious simple-staking URL that contains a malicious regular expression in the URL that crashes the user's browser upon viewing.
If this filter code were ever changed to run on the server (through Next.js's server-side rendering), an attacker could use a malicious regular expression to take down the app.
Alternatively, if the code was changed to save filters in client-side storage (like localStorage
), an attacker could craft a malicious URL that would cause the app to be unusable for a user until they clear their browser data.
Recommendations
Replace the code so it does not use regular expressions — for example:
const filter = filter.search.toLowerCase();
return (fp.description?.moniker ?? "").toLowerCase().includes(filter) || fp.btcPk.toLowerCase().includes(filter)
Remediation
This issue has been acknowledged by Babylon Labs, and a fix was implemented in commit 11d4972d↗.