nodemailer 7.0.9 → 7.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
2
|
+
"packages": {
|
|
3
|
+
".": {
|
|
4
|
+
"release-type": "node",
|
|
5
|
+
"package-name": "nodemailer",
|
|
6
|
+
"pull-request-title-pattern": "chore${scope}: release ${version} [skip-ci]"
|
|
7
|
+
}
|
|
7
8
|
}
|
|
8
|
-
}
|
|
9
9
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# CHANGELOG
|
|
2
2
|
|
|
3
|
+
## [7.0.11](https://github.com/nodemailer/nodemailer/compare/v7.0.10...v7.0.11) (2025-11-26)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Bug Fixes
|
|
7
|
+
|
|
8
|
+
* prevent stack overflow DoS in addressparser with deeply nested groups ([b61b9c0](https://github.com/nodemailer/nodemailer/commit/b61b9c0cfd682b6f647754ca338373b68336a150))
|
|
9
|
+
|
|
10
|
+
## [7.0.10](https://github.com/nodemailer/nodemailer/compare/v7.0.9...v7.0.10) (2025-10-23)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* Increase data URI size limit from 100KB to 50MB and preserve content type ([28dbf3f](https://github.com/nodemailer/nodemailer/commit/28dbf3fe129653f5756c150a98dc40593bfb2cfe))
|
|
16
|
+
|
|
3
17
|
## [7.0.9](https://github.com/nodemailer/nodemailer/compare/v7.0.8...v7.0.9) (2025-10-07)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -4,9 +4,10 @@
|
|
|
4
4
|
* Converts tokens for a single address into an address object
|
|
5
5
|
*
|
|
6
6
|
* @param {Array} tokens Tokens object
|
|
7
|
+
* @param {Number} depth Current recursion depth for nested group protection
|
|
7
8
|
* @return {Object} Address object
|
|
8
9
|
*/
|
|
9
|
-
function _handleAddress(tokens) {
|
|
10
|
+
function _handleAddress(tokens, depth) {
|
|
10
11
|
let isGroup = false;
|
|
11
12
|
let state = 'text';
|
|
12
13
|
let address;
|
|
@@ -87,7 +88,7 @@ function _handleAddress(tokens) {
|
|
|
87
88
|
// Parse group members, but flatten any nested groups (RFC 5322 doesn't allow nesting)
|
|
88
89
|
let groupMembers = [];
|
|
89
90
|
if (data.group.length) {
|
|
90
|
-
let parsedGroup = addressparser(data.group.join(','));
|
|
91
|
+
let parsedGroup = addressparser(data.group.join(','), { _depth: depth + 1 });
|
|
91
92
|
// Flatten: if any member is itself a group, extract its members into the sequence
|
|
92
93
|
parsedGroup.forEach(member => {
|
|
93
94
|
if (member.group) {
|
|
@@ -299,6 +300,13 @@ class Tokenizer {
|
|
|
299
300
|
}
|
|
300
301
|
}
|
|
301
302
|
|
|
303
|
+
/**
|
|
304
|
+
* Maximum recursion depth for parsing nested groups.
|
|
305
|
+
* RFC 5322 doesn't allow nested groups, so this is a safeguard against
|
|
306
|
+
* malicious input that could cause stack overflow.
|
|
307
|
+
*/
|
|
308
|
+
const MAX_NESTED_GROUP_DEPTH = 50;
|
|
309
|
+
|
|
302
310
|
/**
|
|
303
311
|
* Parses structured e-mail addresses from an address field
|
|
304
312
|
*
|
|
@@ -311,10 +319,18 @@ class Tokenizer {
|
|
|
311
319
|
* [{name: 'Name', address: 'address@domain'}]
|
|
312
320
|
*
|
|
313
321
|
* @param {String} str Address field
|
|
322
|
+
* @param {Object} options Optional options object
|
|
323
|
+
* @param {Number} options._depth Internal recursion depth counter (do not set manually)
|
|
314
324
|
* @return {Array} An array of address objects
|
|
315
325
|
*/
|
|
316
326
|
function addressparser(str, options) {
|
|
317
327
|
options = options || {};
|
|
328
|
+
let depth = options._depth || 0;
|
|
329
|
+
|
|
330
|
+
// Prevent stack overflow from deeply nested groups (DoS protection)
|
|
331
|
+
if (depth > MAX_NESTED_GROUP_DEPTH) {
|
|
332
|
+
return [];
|
|
333
|
+
}
|
|
318
334
|
|
|
319
335
|
let tokenizer = new Tokenizer(str);
|
|
320
336
|
let tokens = tokenizer.tokenize();
|
|
@@ -339,7 +355,7 @@ function addressparser(str, options) {
|
|
|
339
355
|
}
|
|
340
356
|
|
|
341
357
|
addresses.forEach(address => {
|
|
342
|
-
address = _handleAddress(address);
|
|
358
|
+
address = _handleAddress(address, depth);
|
|
343
359
|
if (address.length) {
|
|
344
360
|
parsedAddresses = parsedAddresses.concat(address);
|
|
345
361
|
}
|
|
@@ -575,14 +575,27 @@ class MailComposer {
|
|
|
575
575
|
return element;
|
|
576
576
|
}
|
|
577
577
|
|
|
578
|
-
if (dataUrl.length >
|
|
579
|
-
//
|
|
578
|
+
if (dataUrl.length > 52428800) {
|
|
579
|
+
// 52428800 chars = 50MB limit for data URL string (~37.5MB decoded image)
|
|
580
|
+
// Extract content type before rejecting to preserve MIME type
|
|
581
|
+
let detectedType = 'application/octet-stream';
|
|
582
|
+
const commaPos = dataUrl.indexOf(',');
|
|
583
|
+
|
|
584
|
+
if (commaPos > 0 && commaPos < 200) {
|
|
585
|
+
// Parse header safely with size limit
|
|
586
|
+
const header = dataUrl.substring(5, commaPos); // skip 'data:'
|
|
587
|
+
const parts = header.split(';');
|
|
588
|
+
if (parts[0] && parts[0].includes('/')) {
|
|
589
|
+
detectedType = parts[0].trim();
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
580
593
|
// Return empty content for excessively long data URLs
|
|
581
594
|
return Object.assign({}, element, {
|
|
582
595
|
path: false,
|
|
583
596
|
href: false,
|
|
584
597
|
content: Buffer.alloc(0),
|
|
585
|
-
contentType: element.contentType ||
|
|
598
|
+
contentType: element.contentType || detectedType
|
|
586
599
|
});
|
|
587
600
|
}
|
|
588
601
|
|
|
@@ -1147,8 +1147,8 @@ class SMTPConnection extends EventEmitter {
|
|
|
1147
1147
|
}
|
|
1148
1148
|
notify = notify.map(n => n.trim().toUpperCase());
|
|
1149
1149
|
let validNotify = ['NEVER', 'SUCCESS', 'FAILURE', 'DELAY'];
|
|
1150
|
-
let
|
|
1151
|
-
if (
|
|
1150
|
+
let invalidNotify = notify.filter(n => !validNotify.includes(n));
|
|
1151
|
+
if (invalidNotify.length || (notify.length > 1 && notify.includes('NEVER'))) {
|
|
1152
1152
|
throw new Error('notify: ' + JSON.stringify(notify.join(',')));
|
|
1153
1153
|
}
|
|
1154
1154
|
notify = notify.join(',');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nodemailer",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.11",
|
|
4
4
|
"description": "Easy as cake e-mail sending from your Node.js applications",
|
|
5
5
|
"main": "lib/nodemailer.js",
|
|
6
6
|
"scripts": {
|
|
@@ -26,20 +26,20 @@
|
|
|
26
26
|
},
|
|
27
27
|
"homepage": "https://nodemailer.com/",
|
|
28
28
|
"devDependencies": {
|
|
29
|
-
"@aws-sdk/client-sesv2": "3.
|
|
29
|
+
"@aws-sdk/client-sesv2": "3.940.0",
|
|
30
30
|
"bunyan": "1.8.15",
|
|
31
31
|
"c8": "10.1.3",
|
|
32
|
-
"eslint": "
|
|
33
|
-
"eslint-config-prettier": "
|
|
34
|
-
"globals": "
|
|
32
|
+
"eslint": "9.39.1",
|
|
33
|
+
"eslint-config-prettier": "10.1.8",
|
|
34
|
+
"globals": "16.5.0",
|
|
35
35
|
"libbase64": "1.3.0",
|
|
36
36
|
"libmime": "5.3.7",
|
|
37
37
|
"libqp": "2.1.1",
|
|
38
38
|
"nodemailer-ntlm-auth": "1.0.4",
|
|
39
|
-
"prettier": "
|
|
39
|
+
"prettier": "3.6.2",
|
|
40
40
|
"proxy": "1.0.2",
|
|
41
41
|
"proxy-test-server": "1.0.0",
|
|
42
|
-
"smtp-server": "3.
|
|
42
|
+
"smtp-server": "3.16.1"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=6.0.0"
|