[Pkg-javascript-devel] Bug#1120717: trixie-pu: package node-nodemailer/6.10.0+~6.4.17-1+deb13u1
Yadd
yadd at debian.org
Sat Nov 15 07:39:21 GMT 2025
Package: release.debian.org
Severity: normal
Tags: trixie
X-Debbugs-Cc: node-nodemailer at packages.debian.org, yadd at debian.org
Control: affects -1 + src:node-nodemailer
User: release.debian.org at packages.debian.org
Usertags: pu
[ Reason ]
node-nodemailer is vulnerable due to improper handling of specially
formatted recipient email addresses.
[ Impact ]
Medium vulnerability
[ Tests ]
Patch contains new tests
[ Risks ]
Low risk, test coverage is good and patch isn't complex
[ Checklist ]
[X] *all* changes are documented in the d/changelog
[X] I reviewed all changes and I approve them
[X] attach debdiff against the package in (old)stable
[X] the issue is verified as fixed in unstable
[ Changes ]
Better address parsing
Cheers,
Xavier
-------------- next part --------------
diff --git a/debian/changelog b/debian/changelog
index ba226b5..b4fb060 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -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 <yadd at debian.org> 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 --git a/debian/patches/CVE-2025-13033.patch b/debian/patches/CVE-2025-13033.patch
new file mode 100644
index 0000000..687b657
--- /dev/null
+++ b/debian/patches/CVE-2025-13033.patch
@@ -0,0 +1,141 @@
+Description: Fix addressparser handling of quoted nested email addresses
+Author: Andris Reinman <andris at reinman.eu>
+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 <yadd at debian.org>
+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 <addresses>, (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 at 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 at gmail.com x"@internal.domain';
++ let result = addressparser(input);
++ // Should preserve full address, NOT extract xclow3n at gmail.com
++ assert.strictEqual(result.length, 1);
++ assert.strictEqual(result[0].address.includes('@internal.domain'), true);
++ assert.strictEqual(result[0].address, 'xclow3n at gmail.com x at internal.domain');
++ });
++
++ it('should handle quoted local-part with attacker domain (security)', () => {
++ let input = '"user at 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 at attacker.com@legitimate.com');
++ });
++
++ it('should handle multiple @ in quoted local-part (security)', () => {
++ let input = '"a at b@c"@example.com';
++ let result = addressparser(input);
++ // Should not extract a at b or b at c
++ assert.strictEqual(result.length, 1);
++ assert.strictEqual(result[0].address, 'a at b@c at example.com');
++ });
++
++ it('should handle quoted local-part with angle brackets', () => {
++ let input = 'Name <"user at 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 at domain.com"@example.com');
++ });
+ });
diff --git a/debian/patches/series b/debian/patches/series
index 37d5831..40dc79a 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,3 +1,4 @@
drop-timeout-based-test.patch
#fix-test-for-proxy-2.patch
change-test-ports.patch
+CVE-2025-13033.patch
More information about the Pkg-javascript-devel
mailing list