Jun 15, 2026·6 min read·2 visits
Nodemailer's disableFileAccess and disableUrlAccess security flags are bypassed when using jsonTransport or the attachDataUrls feature, enabling unauthorized local file reads and server-side request forgery.
Nodemailer prior to version 8.0.9 contains a security control bypass vulnerability. Transport-level configuration parameters designed to restrict local file system access and remote URL requests are not propagated to all content-resolution execution paths. This failure allows unauthorized local file inclusion and server-side request forgery when the application utilizes specific transports or processing flags.
Nodemailer is a widely utilized package within the Node.js ecosystem for handling SMTP and alternative email transport operations. To mitigate security risks associated with dynamically defined attachments and message structures, Nodemailer exposes two critical security configuration options: disableFileAccess and disableUrlAccess. When enabled, these parameters are intended to act as security boundaries, preventing unauthorized access to the host's local file system and blocking arbitrary outbound HTTP or HTTPS requests.
However, a security control bypass exists in versions of Nodemailer preceding version 8.0.9. The vulnerability is characterized by a failure to propagate these access-restriction flags across all internal content-resolution pathways. Specifically, when an application utilizes the jsonTransport configuration or relies on pre-processing options such as attachDataUrls, Nodemailer performs resource pre-resolution outside of the standard security filter architecture.
This bypass allows attackers who can control the structured elements of an email (such as attachment paths or body properties) to retrieve local system files and initiate outbound network connections. This behavior completely bypasses the security controls established by developers, transforming a restricted mail utility into a vector for local file inclusion (LFI) and Server-Side Request Forgery (SSRF).
The root cause of this vulnerability lies in the architectural divergence between standard message streaming paths and serialization/pre-resolution paths. In a conventional SMTP or file-based transport sequence, file and URL validation is performed inside lib/mime-node/index.js during the _getStream() execution cycle. The transport explicitly transfers its configuration parameters to the mime-node instance, which evaluates disableFileAccess and disableUrlAccess immediately before opening filesystem descriptors or initializing TCP connections.
Conversely, when jsonTransport is configured, Nodemailer bypasses the normal streaming process to output a serialized JSON string representing the email structure. This transport delegates serialization to a normalization workflow defined in lib/mailer/mail-message.js via the resolveAll() function. The purpose of resolveAll() is to evaluate and flatten any lazy or asynchronously defined content properties, such as attachment arrays, inline images, or complex text blocks, prior to compiling the final output.
During this normalization process, resolveAll() iterates over individual components of the message and invokes the utility helper function shared.resolveContent() from lib/shared/index.js. This helper handles the low-level retrieval of resources, directly invoking fs.createReadStream() for file paths and nmfetch() for HTTP/HTTPS requests. Because shared.resolveContent() was designed as a low-level utility, it does not receive, evaluate, or enforce the configuration context containing the disableFileAccess and disableUrlAccess policy restrictions, leading to a complete security bypass.
The execution flow and omission can be traced through the following code comparisons. In vulnerable versions (< 8.0.9), lib/shared/index.js resolved the local or remote contents without checking the transport's restrictions.
// Vulnerable Implementation (lib/shared/index.js)
function resolveContent(data, key, callback) {
let content = data[key];
if (content && content.path) {
// BUG: Directly resolves the local file path without validation
let stream = fs.createReadStream(content.path);
// ... stream reading logic ...
} else if (content && content.href) {
// BUG: Directly fetches the remote URL without checking policy
let req = nmfetch(content.href);
// ... fetch logic ...
}
}During jsonTransport invocation, lib/mailer/mail-message.js triggers this helper directly during the normalization phase:
// lib/mailer/mail-message.js (resolveAll execution flow)
resolveAll(callback) {
// ... loops over attachments, html, text ...
shared.resolveContent(attachment, 'path', (err, data) => {
// The configuration options are not passed to shared.resolveContent()
// Results in automatic, unauthorized file resolution into base64
});
}To correct this vulnerability, the internal architecture was refactored to pass the transport option context down through the resolution chain. The code below represents the conceptual fix deployed in version 8.0.9:
// Patched Implementation (lib/shared/index.js)
function resolveContent(data, key, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
let content = data[key];
// Verify local file access policy before reading
if (content && content.path) {
if (options.disableFileAccess) {
return callback(new Error('EFILEACCESS'));
}
let stream = fs.createReadStream(content.path);
// ...
}
// Verify outbound request policy before fetching
if (content && content.href) {
if (options.disableUrlAccess) {
return callback(new Error('EURLACCESS'));
}
let req = nmfetch(content.href);
// ...
}
}An attacker can exploit this vulnerability if the application permits user input to influence the properties of the message structure, and subsequently uses a vulnerable transport (like jsonTransport) or pre-processing settings (like attachDataUrls).
For a local file inclusion attack, the threat actor submits an email configuration structure containing a specific local file path in the attachment list. Even if the developer configured the transport with disableFileAccess: true, Nodemailer's serialization flow ignores this policy. The system reads the target file and base64-encodes its contents into the attachment object of the returned JSON string.
For a server-side request forgery attack, the threat actor specifies a sensitive local network resource inside the body href, such as the cloud instance metadata endpoint. When Nodemailer processes the object, it performs a GET request to the endpoint and injects the returned response directly into the serialized body field of the JSON structure, disclosing sensitive session credentials or environment data to the attacker.
The impact of this vulnerability depends heavily on the context in which the mail data is handled and where the serialized JSON string is stored or transmitted. In applications that use jsonTransport to buffer messages in external queue systems or databases, an attacker can extract any file readable by the Node.js runtime process, including API credentials, SSL certificates, environment variables, and application source code.
From an SSRF perspective, because outbound connections originate directly from the application server, this vulnerability enables attackers to bypass network perimeters. Attackers can scan local network ranges, query metadata services, and interact with internal administrative tools that trust localhost or local subnet connections.
This vulnerability is assigned a CVSS score of 5.4 (Medium). It requires low privileges to execute, has low complexity, and does not require user interaction. However, because it relies on the specific application configurations of using jsonTransport or attachDataUrls, it is not universally exploitable on all Nodemailer installations.
The primary remediation for this vulnerability is upgrading the nodemailer dependency to version 8.0.9 or higher. This version correctly propagates transport-level security policies into the shared content resolution engine, preventing file reads and remote fetches when access flags are set.
If upgrading the library is not immediately possible, developers must validate all input structures before passing them to the mail utility. Applications should implement recursive validation schemas to ensure that attachment definitions do not contain arbitrary string paths or external URLs.
Furthermore, developers should enforce host-level security policies. Operating system permissions should restrict the Node.js process to only the necessary directories, and firewall rules should block unauthorized outbound connections from the application server to internal subnets or cloud provider metadata services.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:L/I:L/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
nodemailer Nodemailer | < 8.0.9 | 8.0.9 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-610 |
| Attack Vector | Network |
| CVSS Score | 5.4 |
| EPSS Score | 0.012 |
| Impact | Information Disclosure / Server-Side Request Forgery |
| Exploit Status | poc |
| KEV Status | Not Listed |
The product uses an externally controlled reference to a resource, allowing an attacker to access unauthorized files or network resources.
PyJWT versions 2.8.0 through 2.12.1 are vulnerable to an unauthenticated Denial of Service (DoS) attack. When verifying detached JSON Web Signatures (JWS) using the unencoded-payload option (RFC 7797, b64=false), the library eagerly decodes the payload segment before verifying the header configuration or the cryptographic signature. This behavior enables a remote, unauthenticated attacker to inject an arbitrarily large payload segment, triggering excessive CPU and memory resource consumption prior to signature validation.
GHSA-268h-hp4c-crq3 is a Carriage Return Line Feed (CRLF) injection vulnerability in the Nodemailer npm package affecting versions up to and including 8.0.8. The library allows arbitrary email header injection when parsing user-controlled comments within list headers (such as List-Unsubscribe or List-ID). This occurs because list headers bypass standard validation by utilizing an internal 'prepared' flag, causing unsanitized newlines to be emitted directly into the outgoing RFC822 mail stream. This exploit allows remote attackers to inject custom, unauthorized mail headers, disrupting signature checks, bypassing filters, or spoofing parameters.
A logic flaw in PyJWT's PyJWKClient class allows remote unauthenticated attackers to trigger a complete authentication outage. By transmitting a volume of JWTs containing randomized, non-existent Key ID (kid) values, attackers force synchronous outbound JWKS resolution queries. When these queries fail or time out, a defect in the error cleanup code overwrites the local cache of valid signing keys with None, causing a denial of service.
A high-severity type-confusion path traversal vulnerability (CVE-2026-49982 / GHSA-7c78-jf6q-g5cm) exists in the node-tmp package version 0.2.6. The vulnerability allows remote attackers to bypass path validation checks by passing non-string data types such as Arrays or duck-typed Objects into options like prefix, postfix, or template. Because the library relies on the .includes() method without verifying the input type, standard array checks evaluate differently than string checks. Downstream string coercion subsequently restores the traversal sequence, allowing files and directories to be created outside the designated temporary directory root. This can result in arbitrary file writes and potential local file execution depending on application context.
CVE-2026-47347 is an open redirect vulnerability affecting multiple TYPO3 CMS versions. The issue resides in GeneralUtility::sanitizeLocalUrl, where an insufficient blocklist validation implementation fails to prevent browsers from normalizing malformed relative paths into external protocol-relative redirections. Attackers can exploit this to conduct phishing, session hijacking, or credential harvesting campaigns.
An authenticated backend user with access to the Recycler module in TYPO3 CMS can bypass write restrictions and restore soft-deleted records on pages or database tables they are not authorized to modify. This vulnerability resides in the core DataHandler class due to missing permission checks during 'undelete' operations.