Skip to content

Commit

Permalink
fix(security): Fix issues described in GHSA-9h6g-pr28-7cqp. Do not us…
Browse files Browse the repository at this point in the history
…e eternal matching pattern if only a few occurences are expected
  • Loading branch information
andris9 committed Feb 1, 2024
1 parent 2c2b46a commit dd8f5e8
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 17 deletions.
54 changes: 54 additions & 0 deletions examples/sec1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/* eslint no-console: 0 */

'use strict';

const nodemailer = require('../lib/nodemailer');

async function main() {
// Create a SMTP transporter object
let transporter = nodemailer.createTransport({
streamTransport: true,
newline: 'windows',
logger: false
});

// Message object
// Message object
let message = {
from: 'Andris <andris@kreata.ee>',

// Comma separated list of recipients
to: 'Andris Reinman <andris.reinman@gmail.com>',
bcc: 'andris@ethereal.email',

// Subject of the message
subject: 'Nodemailer is unicode friendly ✔',

// plaintext body
text: 'Hello to myself!',

// HTML body
html:
'<p><b>Hello</b> to myself <img src="cid:note@example.com"/></p>' +
'<p>Here\'s a nyan cat for you as an embedded attachment:<br/><img src="cid:nyan@example.com"/></p>',

// An array of attachments
attachments: [
{
filename: 'Embeded file',
path: 'data:' + ';t'.repeat(60000)
}
]
};
console.log(message);
console.time('POC - Embedded file');
let info = await transporter.sendMail(message);
console.timeEnd('POC - IMG file');
console.log('Message sent successfully as %s', info.messageId);
info.message.pipe(process.stdout);
}

main().catch(err => {
console.error(err.message);
process.exit(1);
});
43 changes: 43 additions & 0 deletions examples/sec2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/* eslint no-console: 0 */

'use strict';

const nodemailer = require('../lib/nodemailer');

async function main() {
// Create a SMTP transporter object
let transporter = nodemailer.createTransport({
streamTransport: true,
newline: 'windows',
logger: false
});

// Message object
let message = {
attachDataUrls: ['http://localhost:3000/1'],
from: 'Andris <andris@kreata.ee>',

// Comma separated list of recipients
to: 'Andris Reinman <andris.reinman@gmail.com>',
bcc: 'andris@ethereal.email',

// Subject of the message
subject: 'Nodemailer is unicode friendly ✔',

// plaintext body
text: 'Hello to myself!',

// HTML body
html: '"<img;'.repeat(809) + ' c' + ' src=data:r'.repeat(1000)
};
console.time('POC - IMG file');
let info = await transporter.sendMail(message);
console.timeEnd('POC - IMG file');
console.log('Message sent successfully as %s', info.messageId);
info.message.pipe(process.stdout);
}

main().catch(err => {
console.error(err.message);
process.exit(1);
});
2 changes: 1 addition & 1 deletion lib/mail-composer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ class MailComposer {
* @return {Object} Parsed element
*/
_processDataUrl(element) {
let parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
let parts = (element.path || element.href).match(/^data:((?:[^;]*;){0,20}(?:[^,]*)),(.*)$/i);
if (!parts) {
return element;
}
Expand Down
30 changes: 16 additions & 14 deletions lib/mailer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -395,21 +395,23 @@ class Mail extends EventEmitter {
return callback(err);
}
let cidCounter = 0;
html = (html || '').toString().replace(/(<img\b[^>]* src\s*=[\s"']*)(data:([^;]+);[^"'>\s]+)/gi, (match, prefix, dataUri, mimeType) => {
let cid = crypto.randomBytes(10).toString('hex') + '@localhost';
if (!mail.data.attachments) {
mail.data.attachments = [];
}
if (!Array.isArray(mail.data.attachments)) {
mail.data.attachments = [].concat(mail.data.attachments || []);
}
mail.data.attachments.push({
path: dataUri,
cid,
filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
html = (html || '')
.toString()
.replace(/(<img\b[^<>]{0,1024} src\s{0,20}=[\s"']{0,20})(data:([^;]+);[^"'>\s]+)/gi, (match, prefix, dataUri, mimeType) => {
let cid = crypto.randomBytes(10).toString('hex') + '@localhost';
if (!mail.data.attachments) {
mail.data.attachments = [];
}
if (!Array.isArray(mail.data.attachments)) {
mail.data.attachments = [].concat(mail.data.attachments || []);
}
mail.data.attachments.push({
path: dataUri,
cid,
filename: 'image-' + ++cidCounter + '.' + mimeTypes.detectExtension(mimeType)
});
return prefix + 'cid:' + cid;
});
return prefix + 'cid:' + cid;
});
mail.data.html = html;
callback();
});
Expand Down
2 changes: 1 addition & 1 deletion test/smtp-connection/http-proxy-client-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe('HTTP Proxy Client Tests', { timeout: 10 * 1000 }, () => {
});
});

it('should should fail with timeout', (t, done) => {
it('should fail with timeout', (t, done) => {
let proxyServer = proxy(http.createServer());
proxyServer.authenticate = (req, cb) => {
cb(null, req.headers['proxy-authorization'] === 'Basic dGVzdDpwZXN0');
Expand Down
3 changes: 2 additions & 1 deletion test/smtp-connection/smtp-connection-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -423,7 +423,8 @@ describe('SMTP-Connection Tests', () => {
let client = new SMTPConnection({
port: PORT_NUMBER + 3,
ignoreTLS: true,
logger: false
logger: true,
debug: true
});

client.on('error', err => {
Expand Down

0 comments on commit dd8f5e8

Please sign in to comment.