Never include user input-text in welcome emails
This is one of those articles where reading the title is enough. No need to read the rest, just go and make sure you are not breaking this rule on any of your existing websites, and keep in mind to never break it in the future.
If you are not convinced yet, read on. But know that you are now wasting 5 precious minutes you can otherwise spend on making your welcome emails less vulnerable.
Before we move on, let me clarify that this rule applies to welcome emails sent after direct email sign-ups. Sign-ups via OAuth providers like Gmail, Twitter, GitHub, etc. are by default more secured against the vulnerability I am about to discuss.
Here’s what happened to me 👇
I run a micro SaaS called Weightless. Funny enough, all this tool does is collect email addresses and send email messages, so if anyone’s taking their email security seriously, it should be me. And that’s what I thought I was doing.
However, all my security efforts so far have been around making sure none of my users abuse Weightless to send spam to their subscribers. That’s not where the attacker struck! Because to even attempt spamming someone with Weightless, they would need to become a paid user first, and then to slip through my world-class 👀 security filters. Not efficient! Instead, why not make me spam people on their behalf, and for free?
This became possible by me trying to be too helpful too early, even before confirming the email address used at sign-up belonged to the person who signed up.
This is how my typical welcome email used to look:
Now let’s see how the same email turned out after my attacker decided to put some imagination to it:
That’s an actual email my SaaS sent to someone. And there were hundreds more, before Postmark, mailer daemon bless them, paused outgoing emails on my account and reached out to me.
The attack is quite simple in retrospect: the attacker saw I was including some user-input text in the welcome emails, and started a slow brute-force attack, most likely through an automated bot that was going through the list of real email addresses, signing up everyone on it with some irregular time intervals (maybe it was even less sophisticated and I am giving someone some new ideas here!).
There must be countless spammers abusing countless websites with this technique right now. And your website may well be among them if you, like me, decided that your welcome email can contain anything other the the email confirmation link. Or if, for example, you are passing on unconfirmed emails, together with other user-input data like name, company, etc. to your CRM software, or to the hands of your marketing team.
Consider this simple scenario:
You have a sign-up form with name and email inputs on it. Now pair it with a welcome email like this:
Hey NAME, thanks for signing up. Please click here to confirm your email.
So if Joe with the email joe@example.com signs up, they will get this welcome message:
Hey Joe, thanks for signing up. Please click here to confirm your email.
Nothing wrong, right? Wrong!
Here’s what that email looks like when someone is after Joe’s money:
Hey Joe. Here’s your $99 welcome gift! http://example.com/scam, thanks for signing up. Please click here to confirm your email.
To do this, the attacker only needs to enter Joe. Here’s your $99 welcome gift! http://example.com/scam in your name field. You are doing all the rest!
Pure evil!
If you look at my email screenshots again, you will see that, if anything, my attacker was not creative enough, and I believe they could have done much better. I used to display the same user-input text, mailing list name, twice: once in the subject line, and then in the body. And in both instances, the way they phrased it, resulted in an incoherent message:
Welcome to Weightless.so 🪶 Here’s your setup guide for ‘💳 BAM $1966: http://example.com/scam 💳’
Your mailing list 💳 BAM $1966: http://example.com/scam 💳 is ready.
Here’s what my subject line would look like if they put $1966’ welcome gift: http://example.com/scam ‘get it now as the mailing list name:
Welcome to Weightless.so 🪶 Here’s your setup guide for ‘$1966’ welcome gift: http://example.com/scam ‘get it now’
And here’s how their scam link would appear in the body, had they entered created has been, and our $1966 signup prize won you have, <(°.°)> and at http://example.com/scam it as the mailing list name:
Your mailing list created has been, and our $1966 signup prize won you have, <(°.°)> and at http://example.com/scam it is ready.
You see? A little more creativity and I would suddenly be helping someone run a Yoda-themed scam, and it’s not even the baby Yoda! Luckily enough, it’s not too hard to prevent something like that from happening:
Never include any user-input text in welcome emails, or any other type of emails triggered by submitting publicly accessible forms, where the receiver’s email address is part of the submitted data.