Start with the harm, not a challenge widget

A public enquiry form can be abused in several ways. A script may flood staff with fake messages, send links through the form into an inbox, trigger costly notifications, or submit the same message repeatedly. The first decision is which harm is actually occurring and what a normal enquiry looks like. Keep a short sample of redacted submissions, arrival times and delivery outcomes, without collecting unnecessary personal data. Distinguish abusive volume from a genuine busy period, a marketing campaign, or a customer who retries because no confirmation appeared. OWASP advises mapping the threatened endpoint and layering controls, rather than treating every automated request alike. A small firm should protect its staff queue and customer response time while keeping the ordinary route to ask a question usable.

Draw the complete path on one page: browser submission, server validation, spam decision, storage or email delivery, staff review, and customer acknowledgement. A page that displays ‘sent’ before the server has accepted and queued the request creates false confidence. A CAPTCHA that reduces inbox spam but also drops requests from assistive technology or slow connections has moved the problem to customers. Define an accepted enquiry as one that has a traceable server record or reliable queue item, with a visible confirmation to the sender. Define a rejected enquiry as one that is not delivered and receives a recoverable message when the sender may be legitimate. These definitions give the team something to test after every change.

Use server-side limits and cheap checks first

Apply input length and format checks on the server, because a bot can send requests directly without using the visible form. Limit the amount of work a single request can cause: message length, attachments if any, number of outgoing notifications, and expensive lookups. Add a per-endpoint rate limit keyed to more than a single broad signal where appropriate. An IP-only limit may punish several people sharing a connection and may be bypassed by distributed traffic; an email-only limit can be defeated by invented addresses. Choose limits from actual normal submission patterns, including busy periods, then test with staff-controlled traffic. OWASP describes rate limiting as a foundational control but also stresses endpoint context and graduated responses. The goal is to make high-volume abuse expensive while leaving a clear path for a sincere sender.

A simple hidden field or minimum time-to-submit check may catch unsophisticated scripts, but neither proves a visitor is human. Browser-side checks are useful hints, never the sole gate. Keep server logs of the decision category, time and a short request reference so staff can investigate a disputed rejection. Avoid storing the entire message or raw fingerprint merely to tune the filter; decide a retention period and limit access. If the form sends email, the rate limit must protect that send action too, or an attacker may use the endpoint to flood the team or a third party. If the team cannot observe how many requests are accepted, delayed, challenged and rejected, it cannot tell whether a new rule is protecting capacity or simply hiding real demand.

Add a challenge only where the evidence warrants it

If spam continues after cheap controls, consider a risk-based challenge on suspicious requests rather than confronting every visitor. A provider such as Cloudflare Turnstile is an implementation choice, not a guarantee of a human sender. Cloudflare says its browser widget must be paired with a server call to Siteverify; the visible widget alone does not protect the endpoint. The server should validate the returned token before treating the enquiry as accepted. Cloudflare documents that a token is single-use and valid for 300 seconds. A customer who writes a long enquiry can therefore reach an expired token. Design a way to refresh the challenge and resubmit while retaining the customer’s typed message; do not make the person start again or silently discard the enquiry.

Treat the verification service itself as a dependency. Test valid, missing, expired, reused and provider-error cases on a non-production form, then decide what the customer sees in each case. A retry must not produce duplicate staff enquiries if the first submission was actually accepted. The site should also offer an accessible alternative contact path when a challenge cannot be completed; the address or telephone route must be genuinely monitored. OWASP explicitly recommends accessibility alternatives to user-facing challenges. Review any privacy notice and vendor arrangement for the data sent to the challenge service. Do not claim a particular widget is invisible to every person or works in every browser; test with keyboard access, a screen reader, mobile devices and slower connections used by the audience.

Test both a spam burst and a legitimate retry

Imagine a local repair firm receiving a sudden burst of near-identical enquiries. It adds a server limit for repeated submissions and places suspicious requests into a review queue instead of mailing each one to every technician. During the test, a genuine customer sends a long fault description from a shared office network; the form rejects it because a challenge token expired. The correct result is a clear message, retained text, a fresh token route and a single eventual staff record. The team then tests a rapid automated burst and verifies that notification volume remains bounded. These are illustrative test cases, not measured outcomes for a real business. A useful acceptance test checks both sides: abuse is contained and a valid customer reaches a person.

Choose a review rhythm after launch. Each day at first, sample accepted and rejected cases, compare the staff queue with server acceptance records, and record why a rule was adjusted. Look for an abrupt fall in valid enquiries after a protection change, not just a welcome drop in spam. A rule that blocks all traffic can make an abuse chart look perfect while failing the business. Give staff a short procedure for rescuing a legitimate enquiry from quarantine and for escalating repeated attacks without exposing customer content widely. If the team changes the form design, translation, notification service or challenge provider later, rerun the end-to-end tests. The output is a dependable contact channel, not a claim that bots have disappeared.

Choose a response for each result

A practical decision table has more than ‘pass’ and ‘block’. Clearly invalid input can be rejected before it reaches staff, with a field-specific correction for a real sender. High-confidence repeated junk can be throttled or quarantined. Borderline requests can be accepted into a limited review queue without sending repeated alerts. A challenge failure may require a fresh token and a preserved draft. A provider outage needs an explicit operating choice: temporarily offer a monitored alternative channel, pause that form with a clear notice, or apply a carefully limited fallback. The choice depends on the sensitivity and volume of the enquiry; it should be made before an outage. Never show success when the request has merely failed closed or vanished into an unmonitored queue.

Make the staff review queue workable. Show a reason category and submission time beside a redacted preview, allow an authorised person to mark a message as legitimate, and keep that action traceable. Do not automatically treat every link or non-English message as spam: Hong Kong customers may write in Traditional Chinese, English or a mix, and may paste a product page relevant to their question. Evaluate false positives with those normal patterns in mind. If you publish both English and Chinese forms, test each language path end to end, including error text and the alternative contact details. A rule that passes the English test while dropping Chinese enquiries is a business failure, even if aggregate spam counts decline.

Set a small set of operational measures: incoming requests, server-accepted requests, staff-delivered records, quarantined cases, repeated submissions and confirmed legitimate cases recovered from review. Read the numbers together. A fall in delivered messages could mean successful filtering, a broken mail integration or accidental blocking. A rise in retries could mean customers did not see confirmation. Examine a few actual journeys before changing a limit. This prevents a well-intentioned engineer from tuning only for a clean inbox while the sales team loses valuable contact. Keep measurements local to the business and label them with their observation dates; until they exist, treat any expected improvement as a hypothesis.

Before you proceed

  • Does the server, not just the browser, decide whether to accept the request?
  • Can a genuine sender recover from an expired challenge without losing their message?
  • Do acceptance records reconcile with the staff delivery queue?

Sources & further reading