Securing HTML Email Subscribe Forms

Whether you use Vero Forms or create your own, your HTML forms are exposed to the web, allowing any bad actor to attempt to submit data through them. Bad actors can use these forms maliciously in several ways:

  • To add spammy email addresses to your customer database. This can harm your deliverability, bloat your customer database, and cause you to email people you did not intend.
  • To use the inputs in your form to send spam or harmful content to real email addresses, leveraging your sending domain in order to make the emails look legitimate. This second attack is particularly malicious, and can damage your reputation both with email clients and your customers.

Suppose you have an HTML form for email signups that includes a field for the email address, and the person's first name. This HTML looks something like:

 <form action='https://app.getvero.com/forms/form_secret' method='post'> 
  <label for='email'>Email</label>
  <input name='email' type='email' /> 
  <label for='user_firstName'>FirstName</label>
  <input name='user[firstName]' type='text' /> 
  <input type='submit' value='Subscribe' /> 
</form>

And the form itself seems pretty simple:

html form example

This form also triggers an event called subscriber_signed_up. Because you care about keeping a clean email list and follow a double-opt in process, you have a workflow set up that is triggered by this event and sends an email to the signup ensuring that the user wants to continue receiving emails from you. This is a great practice to follow.

Imagine the content for this email:

Hello {{ user.firstName }}, Thank you for signing up for our newsletter content. Please click this link to opt-in to continue receiving emails from us. Sincerly, Our Team

The malicious actor can write a script that takes a bunch of email addresses they want to target and have a bot fill out your form hundreds or thousands of times. Imagine that instead of putting an actual first name into the firstName input in the form, they instead put the text:

! You have won $10 million dollars. Please visit http://example.com/steal_all_your_information to claim your prize.

When the form is submitted, and the event is triggered you will now send out an email to whoever they have filled in your form with and it will begin with:

Hello! You have won $10 million dollars. Please visit http://example.com/steal_all_your_information to claim your prize.

It will be sent via your sending domain, using your from addresses and look completely legitimate to email clients and the people receiving the email.

Mitigate these issues

There are several things you can do to help mitigate these issues:

  • When an email is directly triggered via an html form on your website, avoid using Liquid to personalize that email. If the email doesn't reference any user or event properties, the intended victim will instead receive a fairly harmless opt-in email.
  • Add a honeypot. The previous link goes into more detail, but bots largely process forms in an automated way and will not be able to tell which inputs in the form are hidden and which are visible. By adding an invisible input to the form, and then filtering those users out from your campaigns, you can prevent emailing addresses added by bots.
  • While a honeypot is good, reCaptcha is better. reCaptcha does an amazing job at detecting bots attempting to use your sign up forms. Implementing reCaptcha is beyond the scope of this article, but it is highly recommened.
  • Add field validations. At it's simplest, this might be something like adding maxlength='30' to each input in your form. While bad actors can still work around this by altering the HTML on the page, it may catch some bots and prevent them from adding large amounts of text or long links. You can go further with javascript, and further still if you add a validation step on your own servers before sending that data to Vero.

We strongly recommend taking every possible step to secure your web forms and prevent bad actors from abusing it.

Author

  • Eric
    Customer Support Engineer