VYPR
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.

PackageAffected versionsPatched versions
mailparsernpm
< 3.9.33.9.3

Affected products

1

Patches

1
921a67df4cfb

fix: escape URLs and link text in textToHtml to prevent XSS

https://github.com/nodemailer/mailparserAndris ReinmanJan 28, 2026via ghsa
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, '&quot;');
    +                        // 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('&quot;'), '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('&lt;script&gt;'), '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('&apos;') || 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

News mentions

0

No linked articles in our index yet.