The form you see is not the form that is attacked
A web form is two things: a page that people see and an address on your server that receives the data. Browser-side rules such as required fields and email format checks live in the page. A script that wants to post junk does not use the page; it sends a request straight to the receiving address with whatever fields it likes. MDN calls client-side validation an initial check and a good experience for users but too easy to bypass, and says servers must validate what they receive. OWASP gives the same instruction: validate on the server even when the browser checks the same fields.
That is why a form can have tidy browser rules and still fill with junk. The rules never ran.
- Check whether junk arrives with values the visible form cannot produce.
- Check whether it arrives in bursts at regular intervals, which suggests a script.
- Check whether the receiving address accepts requests from anywhere.
Server rules by allowlist
Define what each field may contain and reject the rest, rather than trying to list bad strings. OWASP advises against trying to recognise every malicious string and recommends checking type, format and length, plus semantic checks such as an end date after a start date. For a contact form that means a required message within a sensible length, a name within a length limit and an email that matches a maintained validation approach. It also means rules that the page itself might not enforce, such as refusing a submission with a hidden field filled in. Validation is not the whole defence against injection; that needs parameterised queries and output encoding, which are separate jobs.
- Set a maximum length for every field.
- Reject unexpected extra fields instead of storing them.
- Show a message in text that names the field and the problem, for real people.
Low-friction controls that fit small forms
Three controls cost real visitors nothing. A hidden decoy field that people never see and scripts often fill; a submission with it filled in is rejected. A minimum fill time: a submission that arrives faster than a person could type is suspect. And a limit on repeat submissions from one source in a short period. These are practical patterns, not features guaranteed by the cited documentation, and each has limits: a decoy field must be hidden from assistive technology and autofill so that real users are never affected, a timing rule must allow for autofill and password managers, and a repeat limit must not block several people behind one shared address. A challenge service is a further option if you already hold its keys; opening an account for one is a separate decision.
- Test each control against genuine submissions, not only against junk.
- Record why each rejection happened, in an internal log, so thresholds can be tuned.
- Do not tell a bot why it was rejected.
What these controls cannot do
They stop script-generated junk and flooding. They do not stop a person who writes unwanted messages by hand, and a determined attacker can adapt. Format validation also does not prove that an email address belongs to the sender; OWASP says plainly that format validation does not prove mailbox access. If submissions are accepted but the notification email never arrives, that is a sending-path fault, not a spam fault, and has its own repair. Treat any claim of "no more spam" with suspicion.
- Decide in advance what level of remaining junk is acceptable.
- Keep a way to review what was rejected for a while after the change.
How the paid job is accepted
Our form job (posted test price £245, untested, paid only after sign-off) covers one form whose receiving code we can inspect. It is accepted when an agreed set of at least twenty junk submissions, posted directly to the form address, is rejected and a set of ten genuine submissions, including a name with an accent, a name with an apostrophe, a single-word name and an address with a plus sign, is accepted. It excludes email delivery, opening accounts with outside services and any guarantee that no junk will ever get through. Send the form description and a few anonymised examples in your first enquiry, not real submissions.
Sources and limits
- OWASP: Input Validation Cheat Sheet Checked 2026-10-11.
- Validate on the server even when the browser checks the same fields; define what is accepted rather than trying to recognise every malicious string; syntactic and semantic validation are both needed; format validation does not prove mailbox access.
- MDN: Client-side form validation Checked 2026-10-11.
- Client-side validation is an initial check and good user experience but is too easy to bypass; a malicious user can alter the network request, so servers must validate.