Version in base suite: 6.10.0+~6.4.17-1 Base version: node-nodemailer_6.10.0+~6.4.17-1 Target version: node-nodemailer_6.10.0+~6.4.17-1+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/n/node-nodemailer/node-nodemailer_6.10.0+~6.4.17-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/n/node-nodemailer/node-nodemailer_6.10.0+~6.4.17-1+deb13u1.dsc changelog | 7 ++ patches/CVE-2025-13033.patch | 141 +++++++++++++++++++++++++++++++++++++++++++ patches/series | 1 3 files changed, 149 insertions(+) diff -Nru node-nodemailer-6.10.0+~6.4.17/debian/changelog node-nodemailer-6.10.0+~6.4.17/debian/changelog --- node-nodemailer-6.10.0+~6.4.17/debian/changelog 2025-01-26 18:09:53.000000000 +0000 +++ node-nodemailer-6.10.0+~6.4.17/debian/changelog 2025-11-15 07:34:41.000000000 +0000 @@ -1,3 +1,10 @@ +node-nodemailer (6.10.0+~6.4.17-1+deb13u1) trixie; urgency=medium + + * Fix addressparser handling of quoted nested email addresses + (Closes: CVE-2025-13033) + + -- Yadd Sat, 15 Nov 2025 08:34:41 +0100 + node-nodemailer (6.10.0+~6.4.17-1) unstable; urgency=medium * New upstream version 6.10.0+~6.4.17 diff -Nru node-nodemailer-6.10.0+~6.4.17/debian/patches/CVE-2025-13033.patch node-nodemailer-6.10.0+~6.4.17/debian/patches/CVE-2025-13033.patch --- node-nodemailer-6.10.0+~6.4.17/debian/patches/CVE-2025-13033.patch 1970-01-01 00:00:00.000000000 +0000 +++ node-nodemailer-6.10.0+~6.4.17/debian/patches/CVE-2025-13033.patch 2025-11-15 07:34:41.000000000 +0000 @@ -0,0 +1,141 @@ +Description: Fix addressparser handling of quoted nested email addresses +Author: Andris Reinman +Origin: upstream, https://github.com/nodemailer/nodemailer/commit/1150d99f +Bug: https://github.com/nodemailer/nodemailer/security/advisories/GHSA-mm7p-fcc7-pg87 +Forwarded: not-needed +Applied-Upstream: 7.0.7, commit:1150d99f +Reviewed-By: Xavier Guimard +Last-Update: 2025-11-15 + +--- a/lib/addressparser/index.js ++++ b/lib/addressparser/index.js +@@ -15,10 +15,12 @@ + address: [], + comment: [], + group: [], +- text: [] ++ text: [], ++ textWasQuoted: [] // Track which text tokens came from inside quotes + }; + let i; + let len; ++ let insideQuotes = false; // Track if we're currently inside a quoted string + + // Filter out , (comments) and regular text + for (i = 0, len = tokens.length; i < len; i++) { +@@ -28,16 +30,25 @@ + switch (token.value) { + case '<': + state = 'address'; ++ insideQuotes = false; + break; + case '(': + state = 'comment'; ++ insideQuotes = false; + break; + case ':': + state = 'group'; + isGroup = true; ++ insideQuotes = false; ++ break; ++ case '"': ++ // Track quote state for text tokens ++ insideQuotes = !insideQuotes; ++ state = 'text'; + break; + default: + state = 'text'; ++ insideQuotes = false; + break; + } + } else if (token.value) { +@@ -51,8 +62,14 @@ + if (prevToken && prevToken.noBreak && data[state].length) { + // join values + data[state][data[state].length - 1] += token.value; ++ if (state === 'text' && insideQuotes) { ++ data.textWasQuoted[data.textWasQuoted.length - 1] = true; ++ } + } else { + data[state].push(token.value); ++ if (state === 'text') { ++ data.textWasQuoted.push(insideQuotes); ++ } + } + } + } +@@ -74,8 +91,12 @@ + // If no address was found, try to detect one from regular text + if (!data.address.length && data.text.length) { + for (i = data.text.length - 1; i >= 0; i--) { +- if (data.text[i].match(/^[^@\s]+@[^@\s]+$/)) { ++ // Security fix: Do not extract email addresses from quoted strings ++ // RFC 5321 allows @ inside quoted local-parts like "user@domain"@example.com ++ // Extracting emails from quoted text leads to misrouting vulnerabilities ++ if (!data.textWasQuoted[i] && data.text[i].match(/^[^@\s]+@[^@\s]+$/)) { + data.address = data.text.splice(i, 1); ++ data.textWasQuoted.splice(i, 1); + break; + } + } +@@ -92,10 +113,13 @@ + // still no address + if (!data.address.length) { + for (i = data.text.length - 1; i >= 0; i--) { +- // fixed the regex to parse email address correctly when email address has more than one @ +- data.text[i] = data.text[i].replace(/\s*\b[^@\s]+@[^\s]+\b\s*/, _regexHandler).trim(); +- if (data.address.length) { +- break; ++ // Security fix: Do not extract email addresses from quoted strings ++ if (!data.textWasQuoted[i]) { ++ // fixed the regex to parse email address correctly when email address has more than one @ ++ data.text[i] = data.text[i].replace(/\s*\b[^@\s]+@[^\s]+\b\s*/, _regexHandler).trim(); ++ if (data.address.length) { ++ break; ++ } + } + } + } +--- a/test/addressparser/addressparser-test.js ++++ b/test/addressparser/addressparser-test.js +@@ -309,4 +309,40 @@ + ]; + assert.deepStrictEqual(addressparser(input), expected); + }); ++ ++ // Security tests for RFC 5321/5322 quoted local-part handling ++ it('should not extract email from quoted local-part (security)', () => { ++ let input = '"xclow3n@gmail.com x"@internal.domain'; ++ let result = addressparser(input); ++ // Should preserve full address, NOT extract xclow3n@gmail.com ++ assert.strictEqual(result.length, 1); ++ assert.strictEqual(result[0].address.includes('@internal.domain'), true); ++ assert.strictEqual(result[0].address, 'xclow3n@gmail.com x@internal.domain'); ++ }); ++ ++ it('should handle quoted local-part with attacker domain (security)', () => { ++ let input = '"user@attacker.com"@legitimate.com'; ++ let result = addressparser(input); ++ // Should route to legitimate.com, not attacker.com ++ assert.strictEqual(result.length, 1); ++ assert.strictEqual(result[0].address.includes('@legitimate.com'), true); ++ assert.strictEqual(result[0].address, 'user@attacker.com@legitimate.com'); ++ }); ++ ++ it('should handle multiple @ in quoted local-part (security)', () => { ++ let input = '"a@b@c"@example.com'; ++ let result = addressparser(input); ++ // Should not extract a@b or b@c ++ assert.strictEqual(result.length, 1); ++ assert.strictEqual(result[0].address, 'a@b@c@example.com'); ++ }); ++ ++ it('should handle quoted local-part with angle brackets', () => { ++ let input = 'Name <"user@domain.com"@example.com>'; ++ let result = addressparser(input); ++ assert.strictEqual(result.length, 1); ++ assert.strictEqual(result[0].name, 'Name'); ++ // When address is in <>, quotes are preserved as part of the address ++ assert.strictEqual(result[0].address, '"user@domain.com"@example.com'); ++ }); + }); diff -Nru node-nodemailer-6.10.0+~6.4.17/debian/patches/series node-nodemailer-6.10.0+~6.4.17/debian/patches/series --- node-nodemailer-6.10.0+~6.4.17/debian/patches/series 2025-01-26 18:06:27.000000000 +0000 +++ node-nodemailer-6.10.0+~6.4.17/debian/patches/series 2025-11-15 07:34:41.000000000 +0000 @@ -1,3 +1,4 @@ drop-timeout-based-test.patch #fix-test-for-proxy-2.patch change-test-ports.patch +CVE-2025-13033.patch