How to prevent email HTML injection in C# and .NET
Time to read: 5 minutes
Every few years, the Open Web Application Security Project (OWASP) publishes a new list of the 10 most common security issues in web applications, called OWASP Top 10. There is one security flaw that has been around since the first edition in 2003, and grabbed the first spot in the 2010, 2013, and 2017 editions, and that security issue is vulnerability to injection attacks. I previously talked about injection attacks in general and more specifically, how dangerous email HTML injection attacks are and how you can prevent them. However, in this post, you'll learn how you can mitigate HTML injection attacks in .NET specifically.
How HTML injection into emails work
HTML injection is a vulnerability where an application accepts user input and then embeds the input into HTML. A malicious user can inject HTML through the user input so that their malicious HTML is embedded into the overall HTML generated by the application. Most commonly, this type of attack is used to embed malicious HTML including JavaScript into a website which makes it a Cross Site Scripting (XSS) attack, but it could also be used to inject malicious HTML into emails.
Emails can be sent using two different content-types, plain text and HTML. If the email is in plain-text, injected HTML will be rendered as text and not rendered as HTML. HTML emails, on the other hand, are at risk, because the injected HTML will be rendered as part of the overall HTML email. What's worse is that some email clients will render style-blocks, which allows the attacker to take further control over how the email looks.
A vulnerable ASP.NET example
Consider this ASP.NET web application where a user can fill out a form to sign up for a newsletter. The form to sign up for the newsletter is rendered using the following Razor code:
The output will be a form that prompts the user for their first name, last name, and email address.
When the user submits the form, the HTTP POST request will be handled by the OnPostAsync
method in the code-behind of the Razor page:
MVC binds the form values to the SignUpForm
property which is used in the OnPostAsync
method.
The OnPostAsync
checks if the form is valid, if so, it generates a string for the email subject and the email body by embedding the user input.
The email is then sent with the generated subject and body to the email address provided by the user, and the web server responds with "Thank you for signing up!" to the user.
If a user signs up for the newsletter, this is the resulting email:
However, if a malicious user enters HTML into the form, the email could look like this:
I achieved this result by entering the following values into the form:
- First name: Your bill is due
- Last name:
<style>*{color: transparent;} #bill{color: #000;} #bill a{color: blue;}</style> <p id="bill">Your bill is due, <a href="https://localhost/malicious_site">Pay now</a> or we will charge a late fee.</p>
- Email Address: [victim's email address]
At the end of the first name field, I added whitespace in an attempt to hide the rest of the subject, and in the last name field, I entered CSS to hide everything, except for my malicious payment notice.
However, when you open the same email on the Gmail client, you'll notice that Gmail filtered out the style block while still rendering the rest of the malicious HTML, which results in an email that is still malicious, but looks more suspicious.
Why HTML injection into emails is dangerous
Your users are at risk when a hacker is able to take control of the emails that your applications send, but what's especially dangerous is that the emails will be coming from your company email address.
When a malicious email comes from your company email, it looks a lot more legitimate, and if your company has legitimate reasons for billing users, that makes it easier to scam unsuspecting victims into paying the hacker.
This is an issue that seems to easily go under the radar. Almost all websites that I have supported in my 7 years of experience, were vulnerable to this. Make sure to check your websites and applications!
How to prevent HTML injection into emails
To stop malicious users from injecting HTML into emails, you can employ the same techniques that you would use to prevent XSS:
- Don't embed user input into emails if you don't have to.
- If you have to embed user input, ALWAYS HTML-encode the user input before embedding it into emails.
- Additionally, you can detect malicious input using regular expressions or other techniques, and reject the request.
So how could the example be fixed? Take a look at this updated OnPostAsync
method:
In addition to injecting the emailSender
parameter using Dependency Injection, a new htmlEncoder
of type HtmlEncoder
is injected into the OnPostAsync
method. The HtmlEncoder-class contains methods to encode and decode HTML. Before embedding the user input into the htmlBody
string, the first name and last name are HTML-encoded using the htmlEncoder.Encode
method. Then, the email is sent as before and the server responds with "Thank you for signing up!".
Submitting the newsletter signup form with the same malicious input will now result in the following email in your inbox:
As you can see, the HTML is no longer rendered by the mail client, and instead shown as plain text. As a result the email looks very suspicious and hopefully will not succeed into tricking users.
Encoding user input with Twilio SendGrid
Twilio SendGrid is our service for sending emails at scale and maximizing deliverability, whether those emails are sent programmatically from your application or via Marketing Campaigns. SendGrid also has your back when it comes to preventing HTML injection, because the user input will be encoded if you're using these SendGrid features:
- You can send emails with Dynamic Transactional Templates where you create the email template in SendGrid beforehand. Then, from your application, you instruct SendGrid to send the emails along with the necessary data for the template. In these templates, you can grab the passed in data using Handlebar templating. The data will be encoded if you use the default double braces
{{ }}
to embed the user input. For example, to embed the contact's first name, you can use{{ firstName }}
. If you really need to, you can output the data without encoding by using the three braces{{{ }}}
, but be careful, this can leave you vulnerable to HTML injection. - Alternatively, you can send emails using Marketing Campaigns Email Designs where you create the email template in SendGrid and send the emails to your contact list. These templates also use Handlebar templating, and the data will be encoded when using the double braces syntax. Instead of passing the data from your application, the data will come from your contact list. See the Twilio SendGrid Marketing Campaigns documentation for information about working with contacts.
If you want to send transactional emails from your application, we recommend using Dynamic Transactional Templates, but there is one more templating feature which is older and does not encode user input by default. You can also send emails with Substitution Tags to embed the user input, however the user input will not be encoded for you, so make sure to encode the user input yourself!
Don't let your users get pwned via email HTML injection
If reading this made you worried about your own applications, I've been there! Leaving your emails vulnerable to HTML injection can easily go under the radar and even vulnerability code scanners may not find it. Hopefully, after reading this post you know what to look for and how to remedy any type of injection attacks in .NET. Never trust user input and always encode it before embedding it into code.
Niels Swimberghe is a Belgian American software engineer and technical content creator at Twilio. Get in touch with Niels on Twitter @RealSwimburger and follow Niels’ personal blog on .NET, Azure, and web development at swimburger.net.
Related Posts
Related Resources
Twilio Docs
From APIs to SDKs to sample apps
API reference documentation, SDKs, helper libraries, quickstarts, and tutorials for your language and platform.
Resource Center
The latest ebooks, industry reports, and webinars
Learn from customer engagement experts to improve your own communication.
Ahoy
Twilio's developer community hub
Best practices, code samples, and inspiration to build communications and digital engagement experiences.