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-2X7J-588G-CCC2

GHSA-2x7j-588g-ccc2: Algorithmic Complexity Denial of Service in Nodemailer

Amit Schendel
Amit Schendel
Senior Security Researcher

Sep 9, 2026·5 min read·30 visits

Executive Summary (TL;DR)

Nodemailer versions prior to 9.1.0 are vulnerable to remote Denial of Service (DoS) due to quadratic time complexity ($O(n^2)$) in the address parser and envelope generation modules, which blocks the single-threaded Node.js event loop.

An algorithmic complexity vulnerability in Nodemailer before version 9.1.0 allows remote attackers to block the Node.js event loop. This denial of service is triggered by processing large or complex lists of email addresses, leading to quadratic resource consumption.

Vulnerability Overview

Nodemailer is a widely adopted module for sending emails within Node.js applications. It relies on internal components such as the addressparser module and the mime-node engine to parse headers, format recipient lists, and construct SMTP-compliant envelopes. These components process inputs that are frequently sourced directly from untrusted clients, such as user registration forms, contact portals, or inbound mail relays.\n\nThe vulnerability arises due to inefficient algorithms implemented within these processing modules. When an application processes address fields containing thousands of elements or specifically structured fragments, the execution time increases quadratically rather than linearly. Because Node.js utilizes a single-threaded execution model, any prolonged synchronous execution blocks the main event loop entirely.\n\nWhile the event loop is blocked, the server cannot process any other incoming requests, network events, or database callbacks. This behavior transforms a standard string-parsing routine into an effective unauthenticated remote denial of service vector. The system remains completely unresponsive until the computation terminates or the node process is terminated by resource exhaustion limits.

Root Cause Analysis

The root cause is divided into three distinct architectural bottlenecks where algorithmic operations scale quadratically ($O(n^2)$) relative to the size of the input.\n\nThe first bottleneck is located in lib/addressparser/index.js during the accumulation of parsed addresses. The parser iterates over parsed address collections and combines them using Array.prototype.concat(). In JavaScript, concat() allocates a new array and copies all existing and new elements to it. Iterating this operation $N$ times over $N$ addresses results in a cumulative copying overhead of $O(n^2)$ complexity.\n\nThe second bottleneck exists within the display-name fragment recombination logic. To resolve unquoted display names containing commas, the parser iterates backward and executes Array.prototype.splice(i, 1) to merge fragments in place. Splicing elements shifts all subsequent elements in the array to fill the gap. For highly fragmented inputs, executing this operation recursively degrades performance quadratically.\n\nThe third bottleneck resides inside the mime-node envelope generator's _convertAddresses() function. To ensure unique recipients, the code executes Array.prototype.some() to scan the output list for existing records. Performing a linear array scan for every new address elements means that processing a list of $N$ recipients requires $O(n^2)$ comparisons. If these recipients are spread across multiple headers, the validation state is continuously rebuilt, exacerbating the performance penalty.

Execution Path and Complexity Bottlenecks

The following architectural flow illustrates how input processing escalates from a string parser to a blocked event loop:\n\nmermaid\ngraph LR\n A["Untrusted Address Input"] --> B["addressparser() Validation"]\n B --> C["Loop with Array.concat()"]\n B --> D["Loop with Array.splice()"]\n C --> E["O(N^2) Accumulation"]\n D --> E\n E --> F["MimeNode._convertAddresses()"]\n F --> G["Linear Array.some() Scan"]\n G --> H["O(N^2) Envelope Deduplication"]\n H --> I["Node.js Event Loop Blocked"]\n\n\nThis diagram outlines the sequential parsing steps and the precise points where the $O(n^2)$ complexity bottlenecks occur inside both addressparser and mime-node.

Code-Level Analysis and Patches

The vulnerabilities were remediated across three distinct performance-focused commits on August 31, 2026. The patches replace quadratic operations with linear alternatives.\n\nCommit 9116da9528c6524cefaed75185602a7e85d20434 resolves the address parser overhead. It replaces the concat accumulation with an in-place .push() loop, lowering allocation overhead to $O(1)$ per element. It also replaces the in-place splice with a single-pass merge accumulator array that is reversed at the end of the execution block:\n\njavascript\n// Vulnerable logic used concat and splice:\n// parsedAddresses = parsedAddresses.concat(handled);\n// parsedAddresses.splice(i, 1);\n\n// Patched logic uses pushing and a reverse operation:\nfor (let i = 0; i < handled.length; i++) {\n parsedAddresses.push(handled[i]);\n}\n\nconst mergedAddresses = [];\nfor (let i = parsedAddresses.length - 1; i >= 0; i--) {\n const current = parsedAddresses[i];\n const next = mergedAddresses.length ? mergedAddresses[mergedAddresses.length - 1] : null;\n if (next && current.address === '' && current.name && !current.group && next.address && next.name) {\n next.name = current.name + ', ' + next.name;\n } else {\n mergedAddresses.push(current);\n }\n}\nmergedAddresses.reverse();\nparsedAddresses = mergedAddresses;\n\n\nCommit 7cc38af418ffa6fc7e86085195ca5ca681694b3e addresses the envelope deduplication lookup overhead. The linear lookups via .some() are replaced with $O(1)$ lookups leveraging a native JavaScript Set:\n\njavascript\n// Patched logic utilizes Set for deduplication\nif (!seenAddresses) {\n seenAddresses = new Set();\n for (let i = 0; i < uniqueList.length; i++) {\n seenAddresses.add(uniqueList[i].address);\n }\n}\n\n// ...\nif (!seenAddresses.has(address.address)) {\n seenAddresses.add(address.address);\n uniqueList.push(address);\n}\n\n\nCommit 34da64282dcdc9b0581c721a27ab2fa226673150 fixes cross-header deduplication by instantiating the seenRecipients set once per envelope cycle instead of recreating it on each individual header call. This change ensures that multi-header emails scale linearly. These combined changes reduce the execution time for 100,000 addresses from over 25 seconds down to under 100 milliseconds.

Exploitation Methodology

Exploitation of this vulnerability requires no special authentication or privileges. The attack vector depends entirely on the application's ingestion of email address lists from untrusted inputs.\n\nAn attacker can construct a payload consisting of a large, comma-separated string containing redundant email addresses. Alternatively, the attacker can format a payload containing highly fragmented, unquoted names with commas to maximize the display-name splicing execution path. An example payload structure is shown below:\n\ntext\nTo: a, b <c@d.com>, a, b <c@d.com>, ... [repeated 50,000 times]\n\n\nWhen the application processes this payload, the Node.js process experiences 100% CPU utilization. Because Node.js is single-threaded, the entire process is blocked. Any health check endpoints will fail to respond, causing load balancers or container orchestrators to mark the service as unhealthy and terminate the container instance, resulting in service disruption.

Impact Assessment

The primary impact of this vulnerability is complete and immediate denial of service. Because the main thread is blocked, any active connections to the application are dropped or timed out, and no new connections can be established.\n\nThis vulnerability does not allow for privilege escalation, remote code execution, or information disclosure. The threat is strictly limited to availability, making it a high-impact reliability concern for production workloads handling mail queues or webhook events.\n\nThe CVSS v3.1 vector string is calculated as CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H, reflecting network-based, unauthenticated, low-complexity denial of service with high availability impact.

Official Patches

NodemailerPull Request containing performance improvements to address parsing and deduplication.

Fix Analysis (3)

Technical Appendix

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

Affected Systems

Applications utilizing Nodemailer versions prior to 9.1.0 that parse untrusted recipient or header arrays.

Affected Versions Detail

Product
Affected Versions
Fixed Version
nodemailer
Nodemailer
< 9.1.09.1.0
AttributeDetail
CWE IDCWE-400
Attack VectorNetwork (Unauthenticated)
CVSS Score7.5
EPSS Score0.00045
ImpactDenial of Service (DoS)
Exploit Statuspoc
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1499Endpoint Denial of Service
Impact
CWE-400
Uncontrolled Resource Consumption

The system does not properly control the allocation and maintenance of resources, allowing an attacker to trigger quadratic resource consumption.

Known Exploits & Detection

GitHub AdvisoryOfficial GitHub Security Advisory describing the quadratic scaling behavior during address parsing.

Vulnerability Timeline

Vulnerability fixes committed to GitHub
2026-08-31
Nodemailer version 9.1.0 released containing patches
2026-08-31
GitHub Security Advisory published
2026-08-31

References & Sources

  • [1]GHSA-2x7j-588g-ccc2 Advisory
  • [2]Nodemailer Release v9.1.0

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

•11 minutes ago•CVE-2026-112937
6.1

CVE-2026-112937: Arbitrary Directory Deletion via TOCTOU Race Condition in filelock ReadWriteLock

A Time-of-Check Time-of-Use (TOCTOU) race condition in the Python `filelock` library (versions 4.1.0 to 4.2.0) allows local unprivileged attackers to cause arbitrary directory deletion by swapping file system targets during lock cleanup or dead owner sweeps.

Alon Barad
Alon Barad
2 views•5 min read
•about 1 hour ago•CVE-2026-112906
4.7

CVE-2026-112906: Mutual Exclusion Bypass via Inode Recycling and Time Tracking Race in filelock

A local race condition and mutual exclusion bypass vulnerability exists in filelock versions 4.1.0 through 4.2.0. On Linux filesystems with rapid inode reuse, a local attacker can manipulate modification timestamps and lock files to cause waiting processes to falsely evict active soft lock markers.

Amit Schendel
Amit Schendel
7 views•6 min read
•about 2 hours ago•CVE-2026-114055
7.5

CVE-2026-114055: Uncontrolled Resource Consumption in vLLM via Unvalidated Multimodal Kwargs

vLLM prior to version 0.31.0 contains an uncontrolled resource consumption vulnerability (CWE-400) in its HTTP API request handling logic. Unauthenticated remote attackers can transmit per-request keyword arguments (`mm_processor_kwargs` and `media_io_kwargs`) that are passed directly into internal multimodal preprocessing pipelines, causing CPU/GPU memory exhaustion and crashing the engine process.

Amit Schendel
Amit Schendel
6 views•5 min read
•about 3 hours ago•CVE-2026-62204
6.6

CVE-2026-62204: Arbitrary Bazaar Package Overwrite in SiYuan via Parameter Mismatch

An insufficient verification of data authenticity vulnerability in SiYuan prior to version 3.7.4 allows an attacker to overwrite arbitrary installed marketplace packages (plugins, widgets, themes, and templates). By providing a mismatched package name and package archive repository URL during a Bazaar installation request, arbitrary file write into trusted plugin directories can be achieved, enabling persistence and execution across application restarts.

Alon Barad
Alon Barad
7 views•5 min read
•about 4 hours ago•CVE-2026-115478
7.1

CVE-2026-115478: Incorrect Authorization and Incomplete Cleanup in obsidian-tc

In obsidian-tc versions 1.0.1 through 1.31.3, memory lifecycle tools fail to validate note ownership prior to rematerializing Markdown files and execute non-atomic SQLite database mutations. An authorized caller can overwrite arbitrary note bodies on disk and cause persistent desynchronization between the database memory graph and physical vault files.

Amit Schendel
Amit Schendel
8 views•5 min read
•about 5 hours ago•CVE-2026-115477
7.1

CVE-2026-115477: Human-in-the-Loop Authorization Bypass in obsidian-tc

A high-severity authorization bypass vulnerability in obsidian-tc allows clients to bypass Human-In-The-Loop (HITL) confirmation prompts over Streamable HTTP deployments. Due to incomplete validation of returned prompt responses, an attacker echoing a signed requestState token can force execution of destructive vault operations even if a human user declines or cancels the prompt.

Alon Barad
Alon Barad
10 views•5 min read