Nothing my front-end people could possibly do would trick me into trusting user input.
but also cross-system context switches, amateur RegExp, escape character (ab|mis)use, etc. can make "user-input" propagate farther than any one team's boundaries.
assertions/test coverage/fuzzing at every boundary so user-input taint analysis can't fail is a requirement for a system that passes user data around more than one time or tech stack.
How so? The backend ALWAYS validates. No communication necessary, whether or not the frontend also validates doesn't matter to the backend. Frontend validation is to improve user experience, nothing more.
and to reduce server load.
>The backend ALWAYS validates.
Exactly. Sometimes in a system so big compartmentalization is required yet meta-communication is inhibited, that comfort-ability can lead to false asserts / assumptions."We always validate - no need for _me_ to do it" type bystander effect / diffusion of responsibility.
The problem with having separate client-side and server-side validation logic is that you (generally) want the rules to be the same, but you end up needing to write them twice, usually in completely different technologies. I have seen many, many cases where the client-side validation and server-side validation got out of sync, and then just like you put it, obscure bugs or security exploits can arise from this.
In general, I think client-side validation should really only be used for the basics, often with respect to type (e.g. the email/URL examples given) and just basic "required" (non-empty) fields. Anything more complicated than that should be done solely server-side in my opinion - e.g. I wouldn't use setCustomValidity with a complex set of client-side rules. What I think is important, though, is to ensure that if the server validation fails that the error message that comes back is not just a single "Bad input!" message, but errors can be keyed by field to ensure you can display field-specific error messages and error highlighting.
Another option I considered back in the day when my backend was on NodeJS is to have the server return the text for a JavaScript validation function before the form itself is actually rendered. This, this function can be run client-side for immediate feedback when the user submits the form, but it's also the exact same logic that is run on the server when the form values are received.