A contact form is a public input channel into a private workflow. It may feed an inbox, ticket system, CRM, spreadsheet, analytics platform, or automation. The visible fields are only the start of the review: hidden metadata, attachments, cookies, logs, spam controls, and downstream integrations can all create privacy and security exposure.
Collect less and explain the purpose
For each field, identify the business purpose and whether the form can work with less information. A general inquiry usually does not need a date of birth, government identifier, payment information, password, or detailed health information. Mark optional fields honestly, provide a route for sensitive matters that is appropriate to the business, and tell the sender how the information will be used and retained. Do not ask users to paste secrets into a free-text message.
Map every destination for a submission, including email forwarding, help-desk integrations, backups, analytics, and logs. Limit staff access to people who handle inquiries, and remove access promptly when roles change. Avoid exposing submissions in predictable URLs or public storage.
Validate input on the server
Client-side checks improve usability but can be bypassed. OWASP's Input Validation guidance recommends validating input as early as possible, using allowlists where practical, defining minimum and maximum lengths, and applying server-side validation because client-side validation alone is not a security control (OWASP Input Validation Cheat Sheet). For a free-text message, accept the characters users reasonably need, set a length limit, and safely encode the content when it is displayed. Validate attachment type, size, and content through a dedicated upload process rather than trusting a file extension.
Do not build database queries, email headers, shell commands, or HTML by concatenating raw form values. Use maintained framework features for parameterized queries, output encoding, mail construction, and uploads. Return a generic confirmation that does not reveal whether a particular account or address exists.
Protect state-changing and authenticated forms
A simple public inquiry may not use a login, but account-support forms, profile changes, saved drafts, and administrative replies can be authenticated actions. OWASP explains that CSRF can trick an authenticated browser into performing an unwanted action and recommends using built-in framework protection or validated CSRF tokens for state-changing requests; it also advises against using GET for state changes (OWASP CSRF Prevention Cheat Sheet). Spam controls do not replace authentication, authorization, CSRF protection, rate limits, and abuse monitoring.
Rate-limit repeated submissions and alert on spikes without blocking all legitimate users behind a shared network. If using a third-party challenge or form provider, review its cookies, network requests, retention, accessibility, and data-processing terms.
Test the entire delivery path
Submit ordinary text, long text, international characters, blank optional fields, and a safe synthetic attachment where supported. Confirm correct delivery, access restrictions, escaping in staff tools, redaction in logs, and deletion from every downstream store. Test that errors do not echo private content or reveal internal addresses. Recheck after changing themes, plugins, mail providers, or CRM integrations. A trustworthy contact form is intentionally small, safely processed, and traceable from submission through deletion.
Sources
- Input Validation Cheat Sheet — OWASP Foundation
- Cross-Site Request Forgery Prevention Cheat Sheet — OWASP Foundation