Skip to content

Commit dd8f5e8

Browse files
committed
fix(security): Fix issues described in GHSA-9h6g-pr28-7cqp. Do not use eternal matching pattern if only a few occurences are expected
1 parent 2c2b46a commit dd8f5e8

File tree

6 files changed

+117
-17
lines changed

6 files changed

+117
-17
lines changed

examples/sec1.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/* eslint no-console: 0 */
2+
3+
'use strict';
4+
5+
const nodemailer = require('../lib/nodemailer');
6+
7+
async function main() {
8+
// Create a SMTP transporter object
9+
let transporter = nodemailer.createTransport({
10+
streamTransport: true,
11+
newline: 'windows',
12+
logger: false
13+
});
14+
15+
// Message object
16+
// Message object
17+
let message = {
18+
from: 'Andris <andris@kreata.ee>',
19+
20+
// Comma separated list of recipients
21+
to: 'Andris Reinman <andris.reinman@gmail.com>',
22+
bcc: 'andris@ethereal.email',
23+
24+
// Subject of the message
25+
subject: 'Nodemailer is unicode friendly ✔',
26+
27+
// plaintext body
28+
text: 'Hello to myself!',
29+
30+
// HTML body
31+
html:
32+
'<p><b>Hello</b> to myself <img src="cid:note@example.com"/></p>' +
33+
'<p>Here\'s a nyan cat for you as an embedded attachment:<br/><img src="cid:nyan@example.com"/></p>',
34+
35+
// An array of attachments
36+
attachments: [
37+
{
38+
filename: 'Embeded file',
39+
path: 'data:' + ';t'.repeat(60000)
40+
}
41+
]
42+
};
43+
console.log(message);
44+
console.time('POC - Embedded file');
45+
let info = await transporter.sendMail(message);
46+
console.timeEnd('POC - IMG file');
47+
console.log('Message sent successfully as %s', info.messageId);
48+
info.message.pipe(process.stdout);
49+
}
50+
51+
main().catch(err => {
52+
console.error(err.message);
53+
process.exit(1);
54+
});

examples/sec2.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/* eslint no-console: 0 */
2+
3+
'use strict';
4+
5+
const nodemailer = require('../lib/nodemailer');
6+
7+
async function main() {
8+
// Create a SMTP transporter object
9+
let transporter = nodemailer.createTransport({
10+
streamTransport: true,
11+
newline: 'windows',
12+
logger: false
13+
});
14+
15+
// Message object
16+
let message = {
17+
attachDataUrls: ['http://localhost:3000/1'],
18+
from: 'Andris <andris@kreata.ee>',
19+
20+
// Comma separated list of recipients
21+
to: 'Andris Reinman <andris.reinman@gmail.com>',
22+
bcc: 'andris@ethereal.email',
23+
24+
// Subject of the message
25+
subject: 'Nodemailer is unicode friendly ✔',
26+
27+
// plaintext body
28+
text: 'Hello to myself!',
29+
30+
// HTML body
31+
html: '"<img;'.repeat(809) + ' c' + ' src=data:r'.repeat(1000)
32+
};
33+
console.time('POC - IMG file');
34+
let info = await transporter.sendMail(message);
35+
console.timeEnd('POC - IMG file');
36+
console.log('Message sent successfully as %s', info.messageId);
37+
info.message.pipe(process.stdout);
38+
}
39+
40+
main().catch(err => {
41+
console.error(err.message);
42+
process.exit(1);
43+
});

lib/mail-composer/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -537,7 +537,7 @@ class MailComposer {
537537
* @return {Object} Parsed element
538538
*/
539539
_processDataUrl(element) {
540-
let parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
540+
let parts = (element.path || element.href).match(/^data:((?:[^;]*;){0,20}(?:[^,]*)),(.*)$/i);
541541
if (!parts) {
542542
return element;
543543
}

lib/mailer/index.js

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -395,21 +395,23 @@ class Mail extends EventEmitter {
395395
return callback(err);
396396
}
397397
let cidCounter = 0;
398-
html = (html || '').toString().replace(/(<img\b[^>]* src\s*=[\s"']*)(data:([^;]+);[^"'>\s]+)/gi, (match, prefix, dataUri, mimeType) => {
399-
let cid = crypto.randomBytes(10).toString('hex') + '@localhost';
400-
if (!mail.data.attachments) {
401-
mail.data.attachments = [];
402-
}
403-
if (!Array.isArray(mail.data.attachments)) {
404-
mail.data.attachments = [].concat(mail.data.attachments || []);
405-
}
406-
mail.data.attachments.push({
407-
path: dataUri,
408-
cid,
409-
filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
398+
html = (html || '')
399+
.toString()
400+
.replace(/(<img\b[^<>]{0,1024} src\s{0,20}=[\s"']{0,20})(data:([^;]+);[^"'>\s]+)/gi, (match, prefix, dataUri, mimeType) => {
401+
let cid = crypto.randomBytes(10).toString('hex') + '@localhost';
402+
if (!mail.data.attachments) {
403+
mail.data.attachments = [];
404+
}
405+
if (!Array.isArray(mail.data.attachments)) {
406+
mail.data.attachments = [].concat(mail.data.attachments || []);
407+
}
408+
mail.data.attachments.push({
409+
path: dataUri,
410+
cid,
411+
filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
412+
});
413+
return prefix + 'cid:' + cid;
410414
});
411-
return prefix + 'cid:' + cid;
412-
});
413415
mail.data.html = html;
414416
callback();
415417
});

test/smtp-connection/http-proxy-client-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ describe('HTTP Proxy Client Tests', { timeout: 10 * 1000 }, () => {
8080
});
8181
});
8282

83-
it('should should fail with timeout', (t, done) => {
83+
it('should fail with timeout', (t, done) => {
8484
let proxyServer = proxy(http.createServer());
8585
proxyServer.authenticate = (req, cb) => {
8686
cb(null, req.headers['proxy-authorization'] === 'Basic dGVzdDpwZXN0');

test/smtp-connection/smtp-connection-test.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ describe('SMTP-Connection Tests', () => {
423423
let client = new SMTPConnection({
424424
port: PORT_NUMBER + 3,
425425
ignoreTLS: true,
426-
logger: false
426+
logger: true,
427+
debug: true
427428
});
428429

429430
client.on('error', err => {

0 commit comments

Comments
 (0)