basic-ftp is vulnerable to client-side denial of service when parsing FTP control-channel multiline responses.
A malicious or compromised FTP server can send an unterminated multiline response during the initial FTP banner phase, before authentication. The client keeps appending attacker-controlled data into FtpContext._partialResponse and repeatedly reparses the accumulated buffer without enforcing a maximum control response size.
As a result, an application using basic-ftp can remain stuck in connect() while memory and CPU usage grow under attacker-controlled input. This can lead to process-level denial of service, container OOM kills, worker restarts, queue backlog, or service degradation in applications that automatically connect to FTP endpoints.
The root cause is that incomplete FTP multiline control responses are buffered without an upper bound.
FtpContext stores incomplete control-channel data in _partialResponse:
https://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/FtpContext.ts#L63-L64
Incoming control-channel data is handled in _onControlSocketData. The implementation concatenates the previous incomplete response with the new chunk, parses the entire accumulated string, and stores parsed.rest back into _partialResponse:
https://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/FtpContext.ts#L328-L340
The relevant flow is:
completeResponse = this._partialResponse + chunk parsed = parseControlResponse(completeResponse) this._partialResponse = parsed.rest
There is no maximum size check before concatenating, before parsing, or before storing parsed.rest.
The parser accepts incomplete multiline responses and returns the entire unterminated multiline group as rest:
https://github.com/patrickjuchli/basic-ftp/blob/50827c73ca6c1d786c97276e47be8a33d0f2277d/src/parseControlResponse.ts#L15-L43
If a server...
5.3.1Exploitability
AV:NAC:LPR:NUI:NScope
S:UImpact
C:NI:NA:H7.5/CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H