CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-6VJ9-MWQ6-2F5V

GHSA-6VJ9-MWQ6-2F5V: Cross-Tenant SMTP Credential Disclosure via Shared-State DNS Cache Pollution in Nodemailer

Alon Barad
Alon Barad
Software Engineer

Sep 28, 2026·7 min read·7 visits

Executive Summary (TL;DR)

A shared-state vulnerability in Nodemailer's global DNS cache allows attackers to poison connection-specific TLS metadata. This redirects victim SMTPS sessions to an attacker-controlled virtual host, disclosing plaintext SMTP credentials.

Nodemailer versions 5.0.0 up to 10.0.1 are vulnerable to process-global state contamination inside the DNS caching subsystem. When SMTPS connections are established in a multi-tenant Node.js process targeting a shared gateway, a lower-privilege attacker can seed the global DNS cache with a malicious TLS servername. When a victim subsequently resolves the same gateway host, Nodemailer retrieves the polluted servername, overwrites the victim's connection settings, redirects the TLS session to the attacker's virtual host, and transmits the victim's cleartext SMTP credentials directly to the attacker.

Vulnerability Overview

Nodemailer is a widely adopted Node.js module designed for email transmission. To optimize performance and reduce latency during SMTP handshakes, the library implements an internal, process-global DNS cache (dnsCache). This cache mitigates the overhead associated with repeated resolution of target SMTP hosts.

In long-running Node.js processes, such as server-side SaaS platforms or centralized microservices, multiple isolated mail transports often run within a single execution space. If these transports route emails through a shared SMTP relay, they query the same hostname but configure distinct TLS options tailored to their respective domains. This configuration introduces a shared-state attack surface.

The vulnerability designated as GHSA-6VJ9-MWQ6-2F5V arises from an architectural failure to separate concerns within this global DNS cache. Specifically, connection-specific TLS configuration options are stored alongside network-specific DNS records. When multiple independent tenants utilize the shared cache, this design flaw allows a low-privilege attacker to contaminate the cache, leading to cross-tenant connection hijacking and credential disclosure.

Root Cause Analysis

The root cause of GHSA-6VJ9-MWQ6-2F5V is the storage of connection-specific TLS metadata within a process-global cache keyed only by the target hostname. Nodemailer maintains this cache inside src/shared/index.ts using a standard JavaScript Map object named dnsCache. This cache maps host string keys directly to DnsCacheValue structures.

The structural vulnerability lies in the definition of the DnsCacheValue interface, which encapsulates the TLS servername option. When a transport resolves a hostname using resolveHostname(), Nodemailer retrieves the dynamic TLS options provided by that specific connection attempt. If a cache miss occurs, the library populates the global dnsCache with the resolved IP addresses and binds the connection-specific servername to that entry.

const value: DnsCacheValue = {
    addresses: allAddresses,
    servername: options.servername || host
};

Upon subsequent connection attempts to the same host within the five-minute Time-To-Live (TTL), Nodemailer triggers a cache hit. The formatDNSValue() utility extracts the cached value, copying the stale, tenant-specific servername directly into the returned lookup result.

const formatDNSValue = (value: DnsCacheValue | undefined, extra?: Partial<ResolvedHostname>): ResolvedHostname | undefined => {
    return Object.assign(
        {
            servername: value.servername,
            host,
            _addresses: addresses
        },
        extra || {}
    );
}

This behavior corrupts the target parameters for any subsequent connection using the same host. During connection initialization inside src/smtp-connection/index.ts, Nodemailer's _resolveAndConnect() loop iterates over the keys of the returned DNS resolution object and blindly overwrites the existing connection options.

for (const key of Object.keys(resolved!)) {
    if (key.charAt(0) !== '_' && (resolved as { [key: string]: any })[key]) {
        (opts as { [key: string]: any })[key] = (resolved as { [key: string]: any })[key];
    }
}

This routine replaces the correct, transport-specific opts.servername configuration of the second tenant with the stale, poisoned servername from the cache.

Code Analysis & Patch Diff

To remediate this architectural vulnerability, the developers decoupled connection-level metadata from the shared network cache. The security patch was applied in commit a6512dbcb3c6e7f2f70d3acccc5752defe3c61fe.

Below is the code modification in src/shared/index.ts illustrating the removal of the state-sharing property.

// Vulnerable structure definition
export interface DnsCacheValue {
    addresses: string[];
-   servername: string | false;
}
 
// Patched formatting helper
const formatDNSValue = (value: DnsCacheValue | undefined, extra?: Partial<ResolvedHostname>): ResolvedHostname | undefined => {
    return Object.assign(
        {
-           servername: value.servername,
            host,
            _addresses: addresses
        },
        extra || {}
    );
}

The patched implementation dynamically computes the TLS servername at the invocation of resolveHostname() instead of serializing it into the global cache. This guarantees that each calling transport maintains its independent server name metadata.

const host = options.host;
+ // The TLS server name belongs to the connection asking, not to the host it resolves.
+ // The cache is shared by every transport of the process and keyed by host alone.
+ const servername = options.servername || host;

When returning cached values, the dynamic, connection-specific servername is passed back on-the-fly to prevent any cross-tenant leakage.

return callback(
    null,
    formatDNSValue(cached.value, {
+       servername,
        cached: true
    })
);

This fix is architecturally complete. By purging the servername attribute entirely from the stored cache schema, the library eliminates the attack vector. There is no residual shared-state channel remaining in the DNS resolution path that can leak connection-specific TLS configuration details.

Exploitation Methodology

Exploitation of GHSA-6VJ9-MWQ6-2F5V requires a multi-tenant Node.js process where separate users configure distinct SMTPS transports targeting a shared gateway. The attack progresses in five logical phases: cache priming, victim lookup, connection routing, certificate validation, and credential extraction.

First, the attacker creates an SMTPS transport pointing to the target relay (e.g., smtp.sharedrelay.test) and sets the tls.servername property to an attacker-controlled domain (e.g., attacker.test). The attacker triggers a connection, forcing Nodemailer to resolve the host and write { addresses, servername: 'attacker.test' } into the global dnsCache.

Second, a victim tenant initiates a connection to the same relay using their legitimate credentials and expected server name (victim.test). Due to the global scope of dnsCache, Nodemailer retrieves the entry primed by the attacker and overwrites the victim's connection options, setting opts.servername to attacker.test.

Third, the victim's transport invokes the native tls.connect(opts) function. This transmits a TLS Client Hello containing the Server Name Indication (SNI) extension configured for attacker.test. The shared gateway parses this SNI and routes the TLS connection directly to the attacker's virtual server.

Fourth, the attacker's server completes the TLS handshake by presenting a valid certificate for attacker.test. Because the victim's validation options were overwritten to expect attacker.test, Node's native validation subsystem successfully validates the certificate chain against the trusted system root authorities.

Fifth, once the secure channel is established, the victim's Nodemailer client initiates the SMTP protocol flow. The client sends an EHLO command, reads the AUTH PLAIN capability from the attacker's server, and transmits its plain SMTP authentication credentials directly across the hijacked session.

Impact Assessment

The security impact of GHSA-6VJ9-MWQ6-2F5V is classified as high confidentiality loss. An attacker who successfully exploits this state pollution can acquire cleartext authentication credentials for other tenants operating within the same Node.js execution environment.

The Common Vulnerability Scoring System (CVSS) v3.1 vector is CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:N, yielding a score of 5.9 (Medium). Although the impact on confidentiality is high, the overall rating is moderated by the high complexity of the attack. Exploitation depends on precise timing within the DNS TTL window, shared infrastructure routing via SNI, and co-location of transports in a single process.

Despite the Medium rating, this vulnerability represents a severe threat to SaaS applications, shared email routing infrastructure, and multi-tenant microservices. If credentials for an enterprise mail relay are compromised, the attacker can leverage them to bypass spam filters, send malicious mail from legitimate domains, and access sensitive corporate communications.

Detection & Mitigation Guidance

Security teams should immediately audit internal Node.js applications to identify instances of the nodemailer package. Applications with dependency versions between 5.0.0 and 10.0.1 must be considered vulnerable if they establish concurrent SMTPS connections to shared hosts.

The primary remediation strategy is upgrading the project's dependency structure to nodemailer version 10.0.2 or higher. This release resolves the underlying caching logic and ensures complete separation of connection-level metadata.

If immediate upgrading is not feasible, organizations can implement several mitigation workarounds. First, developers can bypass the global DNS resolver by using the direct IP address of the SMTP gateway (e.g., 192.0.2.1) in the host parameter, preventing Nodemailer from querying or writing to the global cache. Second, deploying separate Node.js processes for each tenant isolates the memory space and prevents cross-tenant state pollution.

Additionally, monitoring network logs for anomalies in SNI headers—specifically instances where the target IP matches a legitimate SMTP server but the SNI header contains an unrecognized or third-party domain—can help detect ongoing exploitation.

Official Patches

NodemailerOfficial patch commit removing servername from DNS cache
NodemailerRelease v10.0.2 notes

Fix Analysis (1)

Technical Appendix

CVSS Score
5.9/ 10
CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:U/C:H/I:L/A:N

Affected Systems

Node.js applications running multi-tenant Nodemailer instances.SaaS platforms employing shared SMTP relay gateways.

Affected Versions Detail

Product
Affected Versions
Fixed Version
nodemailer
Nodemailer
>= 5.0.0, < 10.0.210.0.2
AttributeDetail
CWE IDCWE-295
Attack VectorNetwork
CVSS5.9 (Medium)
ImpactHigh (Cleartext Credential Disclosure)
Exploit StatusPoC Available
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1557Adversary-in-the-Middle
Credential Access
T1556Modify Authentication Process
Credential Access
CWE-295
Improper Certificate Validation

The product does not validate or incorrectly validates a certificate, which can allow an attacker to spoof a trusted entity by interfering with the connection path.

Vulnerability Timeline

Vulnerable caching logic introduced in version 5.0.0
2018-12-28
Vulnerability remediated by developer
2026-09-09
Patched version 10.0.2 released
2026-09-09
GitHub Security Advisory GHSA-6VJ9-MWQ6-2F5V published
2026-09-28

References & Sources

  • [1]GitHub Security Advisory GHSA-6VJ9-MWQ6-2F5V

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•28 minutes ago•CVE-2026-88932
5.3

CVE-2026-88932: Uncontrolled Resource Consumption (Denial of Service) via orphaned disk writes on aborted uploads in multer

An uncontrolled resource consumption vulnerability exists in the multer middleware for Node.js (versions 2.2.0 through 2.3.0) when handling aborted multipart uploads using disk storage. Due to an asynchronous race condition in path resolution, files can become permanently orphaned on disk, leading to storage exhaustion and denial of service.

Alon Barad
Alon Barad
3 views•6 min read
•about 1 hour ago•CVE-2026-85024
5.9

CVE-2026-85024: Denial of Service via Uncaught Exception in undici WebSocket Client

A high-severity Denial of Service (DoS) vulnerability exists in the undici WebSocket client implementation when processing compressed frames. The vulnerability is caused by a race condition where event listeners, including error handlers, are stripped from the active zlib stream during cleanup before the stream is fully terminated, leading to an unhandled exception.

Alon Barad
Alon Barad
3 views•7 min read
•about 3 hours ago•CVE-2026-83557
5.6

CVE-2026-83557: Polymorphic Deserialization Bypass in FasterXML jackson-databind via java.lang.Comparable

An incomplete denylist vulnerability in FasterXML jackson-databind's DefaultBaseTypeLimitingValidator allows unauthenticated remote attackers to bypass polymorphic type limitations. By declaring properties of type java.lang.Comparable, attackers can instantiate arbitrary Comparable subclasses on the classpath, leading to path traversal, local file access, or application-specific state manipulation.

Alon Barad
Alon Barad
8 views•6 min read
•about 4 hours ago•CVE-2026-101914
6.5

CVE-2026-101914: Authorization Bypass via Case-Insensitive Path Matching in @grpc/grpc-js-xds

An authorization bypass vulnerability exists in the @grpc/grpc-js Node.js package (specifically within the xDS plugin wrapper @grpc/grpc-js-xds) due to a logical error in its Role-Based Access Control (RBAC) path matching component. When case-insensitive path matching is enabled, the matching logic performs a prefix comparison using the startsWith method instead of a strict equality comparison. This logic flaw allows unauthenticated or low-privilege clients with access to a shorter path to gain unauthorized access to longer, more privileged method names that share the same prefix.

Amit Schendel
Amit Schendel
7 views•6 min read
•about 9 hours ago•CVE-2026-61834
4.3

CVE-2026-61834: Prototype Pollution and Mutation of Inherited Built-in Method Objects in scim-patch

A vulnerability in the scim-patch library allows authenticated users to pollute the global JavaScript execution environment. By transmitting a SCIM PATCH operation targeting inherited built-in methods, such as toString, valueOf, or hasOwnProperty, attackers bypass blocklist filters and mutate global prototype objects. This flaw occurs due to the library relying on standard prototype lookup and the 'in' operator during path-resolution and assignment, resolving to shared native functions instead of treating them as missing own-properties.

Alon Barad
Alon Barad
7 views•6 min read
•about 10 hours ago•GHSA-456V-XQ2P-R4CJ
7.8

GHSA-456V-XQ2P-R4CJ: OS Command Injection in code-ollama grep_search Tool

An OS command injection vulnerability in the grep_search tool of the code-ollama package allows remote code execution. This vulnerability is triggered when a local client executes the CLI against a malicious or compromised Ollama server. Due to grep_search being classified as a read-only tool, the CLI executes it automatically in Plan mode without human-in-the-loop validation, leading to zero-interaction local system compromise.

Amit Schendel
Amit Schendel
8 views•5 min read