Skip to main content

Trusting Client-Side Validation

Trusting client-side validation treats UI checks as the security boundary, but any client can be bypassed to send arbitrary requests. Enforce all validation and authorization server-side on every request, treating the client as hostile.

Trusting client-side validation treats checks performed in the browser or mobile app — required fields, value ranges, disabled buttons, hidden form fields, role-based UI hiding — as the actual enforcement of business rules and security. The fatal assumption is that requests come from your client. They do not have to: anyone can craft raw HTTP requests with curl, intercepting proxies, or a modified app.

Why It Happens

Client-side validation is added first for good reasons — fast feedback and a better user experience — and it is easy to assume that because the UI prevents an action, the action is prevented. Duplicating logic on the server feels redundant. Developers forget that the client is fully under the user's control and that the network boundary, not the UI, is where attackers operate.

Why It Hurts

Every client-side control can be removed or altered: disabled buttons re-enabled, hidden fields edited, price or role parameters changed, validation skipped entirely by calling the API directly. If the server trusts these, attackers bypass authorization (accessing other users' data by changing an ID), tamper with values (setting a discount to 100%), submit malformed data the UI would have blocked, and violate invariants the app depends on. The client should be treated as hostile.

Warning Signs

  • Authorization or pricing decisions exist only in front-end code.
  • Security depends on hidden inputs, disabled controls, or UI element visibility.
  • The server accepts requests without re-checking what the UI supposedly enforced.
  • Sending a request outside the official client succeeds where the UI would block it.

Better Alternatives

Make the server the authority: every validation and authorization rule that matters must be enforced server-side, on every request, regardless of what the client did. Keep client-side checks too — for UX — but never as the security boundary; this is defense in depth, not duplication for its own sake. Validate input against schemas on the server, and perform authorization checks against the authenticated identity, never against client-supplied role flags. Verify object ownership on every access to prevent insecure direct object reference.

How to Refactor Out of It

  1. Identify rules currently enforced only in the client (validation, pricing, role gating, ownership).
  2. Reimplement each as an authoritative server-side check on the relevant endpoint.
  3. Derive authorization from the authenticated session, not from request-supplied roles or hidden fields.
  4. Verify resource ownership on every read and write.
  5. Test by calling the API directly with tampered and out-of-policy requests to confirm the server rejects them.
  6. Keep client checks for UX, documenting that they are advisory only.