Back to Blog
high SEVERITY8 min read

How Message-Level Raw Option Bypass happens in Node.js Nodemailer and how to fix it

A high-severity vulnerability in Nodemailer (GHSA-p6gq-j5cr-w38f) allowed attackers to bypass the `disableFileAccess` and `disableUrlAccess` security controls by using the message-level `raw` option, enabling arbitrary file reads and full-response SSRF in delivered emails. The fix upgrades Nodemailer from version 6.10.1 to 9.0.1, closing this bypass at the library level. This is especially critical for applications that allow any user-influenced content to flow into email composition.

O
By Orbis AppSec
Published August 8, 2026Reviewed August 8, 2026

Answer Summary

GHSA-p6gq-j5cr-w38f is a high-severity security bypass vulnerability in Nodemailer (Node.js), mapped to CWE-284 (Improper Access Control). In affected versions (up to 6.x), the message-level `raw` option bypasses the `disableFileAccess` and `disableUrlAccess` guards entirely, allowing an attacker to embed file paths or internal URLs in outgoing emails and receive their contents back — enabling arbitrary local file read and full-response SSRF. The fix is to upgrade Nodemailer to version 9.0.1 or later, where the `raw` option is subject to the same access restrictions as all other message fields.

Vulnerability at a Glance

cweCWE-284 (Improper Access Control)
fixUpgrade Nodemailer from 6.10.1 to 9.0.1, where the `raw` option respects all configured access restrictions
riskArbitrary local file read and full-response Server-Side Request Forgery (SSRF) via crafted email messages
languageJavaScript / Node.js
root causeThe `raw` message option in Nodemailer 6.x was not subject to the same `disableFileAccess`/`disableUrlAccess` enforcement as other message fields
vulnerabilitySecurity Control Bypass (disableFileAccess / disableUrlAccess) via raw message option

How Message-Level Raw Option Bypass Happens in Node.js Nodemailer and How to Fix It


The Problem with "Safe" Security Flags That Aren't

When developers reach for disableFileAccess and disableUrlAccess in Nodemailer, they're doing the right thing: they're explicitly telling the library not to resolve local file paths or make outbound HTTP requests while composing email messages. This is a critical safeguard for any application that lets user-influenced data flow into outgoing emails.

The problem? In Nodemailer 6.x, those flags had a blind spot — and that blind spot was the message-level raw option.

In a project's pnpm-lock.yaml, Trivy flagged nodemailer@6.10.1 as carrying GHSA-p6gq-j5cr-w38f: a high-severity vulnerability where the raw option completely bypasses both disableFileAccess and disableUrlAccess, opening the door to arbitrary local file reads and full-response SSRF embedded directly in delivered email messages.


The Vulnerability Explained

What raw Does — and What It Skipped

Nodemailer's raw option is a power-user feature. Instead of letting Nodemailer compose a MIME message from structured fields (to, from, html, attachments, etc.), you hand it a pre-built raw RFC 2822 message string or stream. Nodemailer is then supposed to deliver it as-is.

The security controls disableFileAccess and disableUrlAccess are enforced during the message composition phase — when Nodemailer processes structured fields and resolves any embedded references (like path: '/etc/passwd' in an attachment, or href: 'http://internal-service/' in an HTML body). Here's an example of how those flags are typically set:

// Intended to be safe — but wasn't in 6.x when using `raw`
const transporter = nodemailer.createTransport({
  host: 'smtp.example.com',
  port: 587,
  disableFileAccess: true,   // Should block local file reads
  disableUrlAccess: true,    // Should block HTTP fetches
});

await transporter.sendMail({
  from: 'app@example.com',
  to: user.email,
  raw: userControlledRawMessage,  // ← bypasses both flags entirely in 6.x
});

In Nodemailer 6.10.1, when you use the raw field, the library short-circuits the normal composition pipeline and delivers the content without running it through the access-control checks that disableFileAccess and disableUrlAccess enforce. The flags are set, the developer believes the application is protected, but the raw path is a completely separate code route that never consults those flags.

The Concrete Attack Scenario

Consider an application that:

  1. Accepts user-provided email content (e.g., a "send this report to a colleague" feature)
  2. Passes that content through to Nodemailer using the raw option for formatting flexibility
  3. Has disableFileAccess: true and disableUrlAccess: true set on the transporter, believing the application is hardened

An attacker who can influence the value passed to raw — even partially, through a template injection, a deserialization flaw, or a misconfigured API endpoint — can craft a raw MIME message that references:

  • Local files: e.g., embedding a reference to /etc/passwd, /app/.env, or any secrets file readable by the Node.js process
  • Internal URLs: e.g., pointing to http://169.254.169.254/latest/meta-data/ (AWS IMDS), internal microservices, or other SSRF targets

Because the raw path skips the access-control checks, Nodemailer resolves those references and includes their full contents in the delivered email message. The attacker receives the exfiltrated data in their inbox.

This is not a theoretical primitive. It is a direct, high-severity data exfiltration and SSRF path that bypasses what developers reasonably believe is a working security control.

Why This Is Especially Dangerous

The danger is compounded by a false sense of security. Developers who set disableFileAccess: true have taken an affirmative action to protect their application. They've read the documentation, they've done the right thing — but in 6.x, that action provides no protection when raw is in play. Automated exploit-development tooling increasingly chains exactly these kinds of "protection that doesn't protect" primitives with other weaknesses to build end-to-end exploits.


The Fix

Upgrading from 6.10.1 to 9.0.1

The fix is a direct version upgrade. In package.json, the specifier changed from ^6.9.14 to ^9.0.1:

- "nodemailer": "^6.9.14",
+ "nodemailer": "^9.0.1",

And in pnpm-lock.yaml, the resolved version moved from 6.10.1 to 9.0.1:

   nodemailer:
-    specifier: ^6.9.14
-    version: 6.10.1
+    specifier: ^9.0.1
+    version: 9.0.1

The integrity hash also changed, confirming a completely different package artifact is now being installed:

-  nodemailer@6.10.1:
-    resolution: {integrity: sha512-Z+iLaBGVaSjbIzQ4pX6XV41HrooLsQ10ZWPUehGmuantvzWoDVBnmsdUcOIDM1t+yPor5pDhVlDESgOMEGxhHA==}
+  nodemailer@9.0.1:
+    resolution: {integrity: sha512-Gwv8SQewT616ZM/URn0H54b8PWo/Wum7md3EW2aWy1lO27+WZCX+Xyak3J+NlmHUJDh5ME+uesJUDRbR3Ye8Bw==}

What Changed in Nodemailer 9.x

In Nodemailer 9.0.1, the raw option is no longer a bypass route. The access-control enforcement for disableFileAccess and disableUrlAccess is applied consistently across all message composition paths, including raw. This means:

  • If disableFileAccess: true is set, file references in raw messages are blocked
  • If disableUrlAccess: true is set, URL fetches triggered by raw message content are blocked
  • The security model developers expected is now the security model they actually get

Why Two Files Were Changed

Both package.json and pnpm-lock.yaml required changes because pnpm uses a deterministic lockfile. Changing only package.json would update the version range specifier but leave the old resolved version (6.10.1) pinned in the lockfile. Both files must be updated together to ensure the correct version is actually installed in all environments, including CI/CD pipelines and production deployments.


Key Takeaways

  • disableFileAccess and disableUrlAccess in Nodemailer 6.x are not enforced when the raw message option is used — setting them does not protect you if raw is in your code path.
  • The raw option is a high-risk API surface: any user-influenced data reaching raw in Nodemailer 6.x is a direct path to file read and SSRF, bypassing all configured security controls.
  • The pnpm-lock.yaml lockfile must be updated alongside package.json — updating only the version range in package.json leaves the vulnerable 6.10.1 pinned in the lockfile and installed in practice.
  • False security is worse than acknowledged insecurity: the presence of disableFileAccess: true in code using vulnerable Nodemailer versions may delay detection of the actual attack surface.
  • Trivy's dependency scanning caught this in pnpm-lock.yaml — scanning lockfiles (not just package.json) is essential because lockfiles contain the actual resolved versions installed in production.

How Orbis AppSec Detected This

  • Source: User-influenced content passed to the raw field in a transporter.sendMail() call — any code path where external or user-provided data reaches the raw message option in Nodemailer 6.x.
  • Sink: Nodemailer's internal message composition pipeline in nodemailer@6.10.1, specifically the raw option handler that resolves file paths and URLs without consulting disableFileAccess or disableUrlAccess.
  • Missing control: The disableFileAccess and disableUrlAccess flags were not applied to the raw message composition code path in Nodemailer 6.x, creating an unguarded route to filesystem access and outbound HTTP requests.
  • CWE: CWE-284 — Improper Access Control (a security control exists but is inconsistently enforced).
  • Fix: Upgraded nodemailer from 6.10.1 to 9.0.1 in both package.json and pnpm-lock.yaml, where the raw option is subject to the same access restrictions as all other message fields.

Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.


Conclusion

GHSA-p6gq-j5cr-w38f is a reminder that security controls are only as strong as their consistent enforcement. Nodemailer's disableFileAccess and disableUrlAccess flags are the right tool for the job — but in versions prior to 9.0.1, the raw option silently voided both of them. For any application composing emails with user-influenced content, this was a direct path to arbitrary file exfiltration and SSRF.

The fix is simple: upgrade to Nodemailer 9.0.1. The lesson is broader: when you rely on a library's security configuration, verify that it applies uniformly across all the API surfaces you use — not just the ones documented in the "safe usage" examples. Automated dependency scanning, as demonstrated here with Trivy detecting this in pnpm-lock.yaml, is an essential layer in catching these gaps before attackers do.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #9

Related Articles

high

How Denial of Service via Crafted Email Headers Happens in Node.js and How to Fix It

A high-severity denial-of-service vulnerability (CVE-2025-14874) in Nodemailer versions prior to 7.0.0 allowed attackers to crash Node.js email-sending services by supplying specially crafted email address headers. The fix upgrades the `nodemailer` dependency in `clay-server` from version 6.10.1 to 9.0.5, closing the attack surface against malformed input. Any application that passes user-influenced data into Nodemailer's address parsing logic is affected and should upgrade immediately.

high

How Message-Level Raw Option Bypass happens in Node.js Nodemailer and how to fix it

A high-severity vulnerability in Nodemailer (versions before 9.0.0) allowed the `raw` message option to completely bypass `disableFileAccess` and `disableUrlAccess` security controls, enabling attackers to read arbitrary files from the server filesystem and perform full-response Server-Side Request Forgery (SSRF) in delivered email messages. Upgrading from `^8.0.10` to `^9.0.4` in `backend/package-lock.json` closes this exploit primitive by enforcing access restrictions consistently across all m

high

How Nodemailer raw option bypass happens in Node.js and how to fix it

A high-severity vulnerability in Nodemailer versions prior to 9.0.1 allowed attackers to bypass the `disableFileAccess` and `disableUrlAccess` security controls using the message-level `raw` option. This bypass enabled arbitrary file reads from the server and full-response Server-Side Request Forgery (SSRF) attacks, potentially exposing sensitive configuration files and internal network resources. The fix involves upgrading Nodemailer from version 8.0.7 to 9.0.1.

high

CVE-2025-14874: Nodemailer DoS via Crafted Email Address Header

CVE-2025-14874 is a high-severity Denial of Service vulnerability in Nodemailer that allows an attacker to crash an application by sending a specially crafted email address header. The vulnerability existed in Nodemailer versions prior to 7.0.11 and was present in the `Dise-ador-experto-master` project's `package-lock.json` dependency on version 6.10.1. Upgrading to Nodemailer 7.0.11 resolves the issue by fixing the underlying header parsing logic that could be exploited to cause unbounded resou

high

ip-address 10.2.0 SSRF: Inconsistent Parsing Bypasses IP Checks

The `ip-address` npm package version 10.2.0 contains an inconsistent parsing vulnerability that allows attackers to bypass IP-based access controls. By representing IPv4 addresses in IPv4-mapped IPv6 notation, attackers can trick applications into allowing requests to blocked internal addresses. Upgrading to 10.3.1 resolves this through stricter address normalization.

high

modelExporter.js Path Traversal via Unsanitized Directory Concatenation

A path traversal vulnerability in `modelExporter.js` allowed attackers to read arbitrary files by injecting traversal sequences into directory and relative path parameters. The `readSourceFile` function concatenated these unsanitized inputs directly into file URLs passed to `fetch()`. The fix introduces strict path normalization that rejects attempts to escape the intended directory.