Medium severity6.1NVD Advisory· Published Mar 3, 2026· Updated Apr 29, 2026
CVE-2026-3455
CVE-2026-3455
Description
Versions of the package mailparser before 3.9.3 are vulnerable to Cross-site Scripting (XSS) via the textToHtml() function due to the improper sanitisation of URLs in the email content. An attacker can execute arbitrary scripts in victim browsers by adding extra quote " to the URL with embedded malicious JavaScript code.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
mailparsernpm | < 3.9.3 | 3.9.3 |
Affected products
1Patches
1921a67df4cfbfix: escape URLs and link text in textToHtml to prevent XSS
2 files changed · +103 −1
lib/mail-parser.js+5 −1 modified@@ -1129,7 +1129,11 @@ class MailParser extends Transform { result.push(textPart); } - result.push(`<a href="${link.url}">${link.text}</a>`); + // Escape quotes in URL to prevent XSS + let safeUrl = link.url.replace(/"/g, '"'); + // Escape HTML entities in link text + let safeText = he.encode(link.text, { useNamedReferences: true }); + result.push(`<a href="${safeUrl}">${safeText}</a>`); last = link.lastIndex; });
test/issue-412-test.js+98 −0 added@@ -0,0 +1,98 @@ +'use strict'; + +const MailParser = require('..').MailParser; +const simpleParser = require('..').simpleParser; + +module.exports['XSS via URL with quotes in href attribute'] = { + 'should escape double quotes in URLs': test => { + const maliciousEmail = `From: attacker@evil.com +To: victim@example.com +Subject: Test +Content-Type: text/plain + +Visit: http://example.com?"onmouseover="alert('XSS')" +`; + + const mailparser = new MailParser(); + mailparser.on('data', () => false); + mailparser.on('end', () => { + // The generated HTML should not contain unescaped quotes that break out of href + test.ok(!mailparser.textAsHtml.includes('"onmouseover='), 'Should not contain unescaped event handler'); + test.ok(mailparser.textAsHtml.includes('"'), 'Should contain escaped quotes'); + test.done(); + }); + mailparser.end(Buffer.from(maliciousEmail)); + }, + + 'should escape HTML entities in link text': test => { + const maliciousEmail = `From: test@example.com +To: user@example.com +Subject: Test +Content-Type: text/plain + +Check: http://example.com/<script>alert(1)</script> +`; + + const mailparser = new MailParser(); + mailparser.on('data', () => false); + mailparser.on('end', () => { + // Link text should have HTML entities escaped + test.ok(!mailparser.textAsHtml.includes('<script>'), 'Should not contain unescaped script tag'); + test.ok(mailparser.textAsHtml.includes('<script>'), 'Should contain escaped script tag'); + test.done(); + }); + mailparser.end(Buffer.from(maliciousEmail)); + }, + + 'should handle URL with single quotes': test => { + const email = `From: test@example.com +To: user@example.com +Subject: Test +Content-Type: text/plain + +Visit: http://example.com?foo='bar' +`; + + const mailparser = new MailParser(); + mailparser.on('data', () => false); + mailparser.on('end', () => { + // Single quotes in href should be escaped in link text + test.ok(mailparser.textAsHtml.includes(''') || mailparser.textAsHtml.includes("'"), 'Should handle single quotes'); + test.ok(mailparser.textAsHtml.includes('href="http://example.com'), 'Should contain valid href'); + test.done(); + }); + mailparser.end(Buffer.from(email)); + }, + + 'should work with simpleParser': async test => { + const maliciousEmail = `From: attacker@evil.com +To: victim@example.com +Subject: Test +Content-Type: text/plain + +Visit: http://example.com?"onclick="alert('XSS')" +`; + + const parsed = await simpleParser(maliciousEmail); + test.ok(!parsed.textAsHtml.includes('"onclick='), 'Should not contain unescaped event handler via simpleParser'); + test.done(); + }, + + 'should preserve valid URLs': test => { + const email = `From: test@example.com +To: user@example.com +Subject: Test +Content-Type: text/plain + +Visit: https://example.com/path?query=value&other=123 +`; + + const mailparser = new MailParser(); + mailparser.on('data', () => false); + mailparser.on('end', () => { + test.ok(mailparser.textAsHtml.includes('href="https://example.com/path?query=value'), 'Should preserve valid URL'); + test.done(); + }); + mailparser.end(Buffer.from(email)); + } +};
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/nodemailer/mailparser/commit/921a67df4cfb38f0b411037d7b26fbd4d5411b08nvdPatchWEB
- gist.github.com/hayageek/7fcb225e3b1ea9a341d560403fbb585anvdExploitThird Party AdvisoryWEB
- github.com/advisories/GHSA-7gmj-h9xc-mcxcghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-3455ghsaADVISORY
- security.snyk.io/vuln/SNYK-JS-MAILPARSER-15204032nvdThird Party AdvisoryWEB
- github.com/nodemailer/mailparser/issues/412nvdIssue TrackingWEB
News mentions
0No linked articles in our index yet.