Tested on Node 22.23.4 and npm 10.9.9

basic-ftp CVE-2026-126345: why npm audit fix leaves the alert open under get-uri

Your audit reports CVE-2026-126345 or CVE-2026-126346 in basic-ftp. You run npm audit fix, but the package stays on 5.3.1. Or you already overrode it to 6.2.1, 6.2.2 or 6.2.3 for an earlier advisory, and Dependabot cannot make another security update.

There are two different restrictions to check:

  • The parent's range. get-uri@6.0.5 requires basic-ftp ^5.0.2. Even get-uri@8.0.1, the latest published version when we checked on 14 November, requires ^5.3.1. Neither range admits the fixes in 6.x. Updating the parent to its latest release does not, by itself, remove that restriction.
  • Your own override. An exact override holds that version in place. 6.2.1 and 6.2.2 remain affected by both new advisories; 6.2.3 fixes the CR/LF advisory below but not the MLSD parser advisory. Existing 6.2.1–6.2.3 overrides may have been added for the earlier high-severity GHSA-c475-qrg2-pj4r, fixed in 6.2.1. An override added for an earlier alert needs a new check when another advisory arrives.

You may never have added an FTP client yourself. Maintainers have reported this chain under Lighthouse CI, browser-download tooling, Firebase tooling and other packages that use a proxy agent: proxy-agent → pac-proxy-agent → get-uri → basic-ftp. Use your own installed tree to find the parent; the package's presence alone does not establish whether your application uses FTP.

Which release fixes which alert?

GitHub published the two new advisories on 12 November; both are Moderate severity. An older High-severity advisory also appears in the audit of basic-ftp 5.3.1, so include it in any decision to keep that version.

AlertAffected releasesFirst fixed releaseWhat the advisory describes
CVE-2026-126345 / GHSA-5pm8-86m8-9m6r≤6.2.36.2.4A crafted fact name in an FTP server's MLSD directory listing makes the parser throw a TypeError.
CVE-2026-126346 / GHSA-r4jh-29pc-gfqr≤6.2.26.2.3Control characters in a password, or a resumed-download path, can throw outside the returned promise and terminate the process.
CVE-2026-102990 / GHSA-c475-qrg2-pj4r (High; published 1 October)≤6.2.06.2.1A crafted Unix-style FTP directory listing makes the parser spend excessive CPU time matching a line.

There was no patched 5.x release in the npm registry on 14 November; its newest 5.x was 5.3.1. The latest published release was 6.2.6, which is the version used in the override example below. The table gives first fixed releases, not a promise that a release has no other vulnerabilities.

Find the copy that your audit sees

Run these in the project's root, after installing its locked dependencies. They are npm commands; a pnpm or Yarn project needs its own package manager's tree and override settings.

node --version
npm --version
npm ls basic-ftp get-uri
npm explain basic-ftp
npm audit --json
npm audit --omit=dev

An audit can exit with a nonzero status because it found a vulnerability. That does not mean the command failed to run. Our 5.3.1 fixtures reported High severity and all three advisories above, including the older Unix-parser finding. Check the basic-ftp finding's GHSA link and installed version; npm can also list several packages that inherit the same vulnerable dependency. Those entries are not necessarily several independent bugs.

npm explain basic-ftp names the path that brought it in. npm ls shows the installed versions and marks overrides. Check every copy, and check the manifest and lockfile named by the original alert. Updating a root lock does not update another workspace's separately maintained lock, a global tool installation, or an already built image.

Compare the complete audit with npm audit --omit=dev. A finding disappearing from that report tells you it is outside npm's non-development dependency report for that installation. It does not prove the package is absent from an image or cannot run in CI, and it does not dismiss a Dependabot alert against the full lockfile.

Why an ordinary update can stop at 5.3.1

For a project that installs get-uri@6.0.5, the parent asks for basic-ftp ^5.0.2: versions from 5.0.2 up to, but excluding, 6.0.0. get-uri@8.0.1 asks for ^5.3.1, which also excludes 6.x. The registry has no newer 5.x to choose.

We tested clean projects with get-uri@6.0.5 and get-uri@8.0.1 as development dependencies. Both installed basic-ftp@5.3.1. Running npm audit fix with install scripts disabled left that version in place in both projects and exited 1. The fixes existed in the registry; the parent's declared range was the restriction.

Do not use npm audit fix --force as a substitute for choosing the change. npm documents that --force can install versions outside your declared ranges, including major changes. In our get-uri 6.0.5 fixture, the audit suggested the force route and said it would install get-uri 4.0.0, an older major release. We did not apply that proposal. Review whatever change npm proposes and run the affected tool's real workflow.

Option 1: update or remove the parent

Prefer a parent release that declares a patched basic-ftp range, or removes the dependency, when one exists for your tool. Verify its resulting tree: get-uri@8.0.1 still uses 5.x, so "the latest get-uri" was not that release on 14 November.

If the parent is an unused development tool, removing it can also remove the chain. Check the lockfile and the CI jobs that used it. This page does not test removing or upgrading Lighthouse CI, Puppeteer, Firebase CLI or another top-level tool.

Option 2: override the transitive version, with a compatibility check

For npm projects whose affected copy is under get-uri, this root setting forces that child to 6.2.6:

{
  "overrides": {
    "get-uri": {
      "basic-ftp": "6.2.6"
    }
  }
}

Merge that setting into your existing package.json; do not replace the whole file or discard other overrides. If get-uri already has a string or version-scoped override, resolve that existing rule before using the command below. If you also have an older flat basic-ftp override, reconcile it with this scoped rule: raise it to the intended fixed version, or remove it only after checking which other copies it covers. If basic-ftp is a direct dependency, update that dependency's declaration instead: npm restricts overrides of direct dependencies.

For a root manifest with no conflicting override rule, the equivalent commands are:

npm pkg set 'overrides.get-uri.basic-ftp=6.2.6'
npm install --ignore-scripts
npm ls basic-ftp
npm audit

--ignore-scripts skips install scripts; it is not a build or compatibility test. Review the manifest and lockfile diff; a different npm version can also introduce unrelated lockfile changes. Then run your normal build and the actual tool that brings in the dependency, using your normal installation policy. Commit both files when the change is accepted. If other parents bring in another copy, this setting does not cover that copy.

This crosses a declared major boundary. It is a compatibility decision, even if the audit turns green. The basic-ftp 6.0.0 release changes the default for FTP data connections: a server cannot direct the transfer to a different host unless the application explicitly enables that behavior. Do not turn that protection off merely to make a test pass.

We ran the commands above against both fixture projects. Each resolved basic-ftp@6.2.6 after the override, and each complete npm audit then reported zero vulnerabilities. That result applies to these small fixture trees. For your project, check that every copy targeted by the change resolves to 6.2.6 and that its basic-ftp finding, including any inherited get-uri finding, is gone from the audit. Unrelated advisories can still make npm audit exit nonzero. This does not establish compatibility with your top-level tool or a clean audit for your project. We exercised get-uri 6.0.5's FTP fallback and HTTP download separately below; we did not exercise get-uri 8.0.1's download behavior.

An override also becomes a restriction you own. Record the reason, the tool path you tested, and when to remove it: a parent release that accepts a patched version, or removal of the chain. Recheck it when a later alert names a newer fixed release.

If you keep the current version

The exposure questions differ:

  • CVE-2026-126345: can an FTP server you connect to supply an MLSD listing to this parser? In get-uri@6.0.5, the FTP handler can fall back to a listing when it cannot obtain the file's modification time with MDTM.
  • CVE-2026-126346: can outside input reach an FTP password, or the remote path of a resumed download? The advisory's throw happens in a socket response handler, so catching only the returned promise was insufficient on the affected version.
  • CVE-2026-102990 / GHSA-c475-qrg2-pj4r: do you accept Unix-style directory listings from an FTP server? The older advisory describes excessive CPU use when that server supplies a crafted listing line. We did not reproduce this older parser vulnerability; account for it separately when considering whether to keep 5.3.1. The tested MLSD fix alone does not address every finding in that version's audit.

Our loopback fixtures on Node 22.23.4 gave these results:

Testbasic-ftp 5.3.1basic-ftp 6.2.6
Parse an MLSD entry with an unknown __proto__ factTypeError: factHandler is not a functionEntry parsed without that throw
Log in with a password containing CR/LF, catching the returned promiseChild process exited 1 with an uncaught exceptionPromise rejected and was caught; child exited 0
get-uri 6.0.5: fetch an FTP file from a server that rejects MDTM and includes that fact in its listingSame parser TypeErrorDownloaded the fixture file
get-uri 6.0.5: fetch an HTTP fileDownload succeededDownload succeeded

These tests demonstrate the FTP failure paths in the tested client and get-uri 6.0.5. The HTTP row is a control for that request, not a reachability verdict for a whole application. We did not test the advisory's resumed-download path.

Trace the URLs, proxy configuration and credentials used by the tool in the environment where it runs. A development-only dependency can still execute with CI permissions. A successful HTTP request in our fixture does not establish that your tool will never choose FTP.

If you decide to defer an upgrade, record the installed version, advisory, dependency path, evidence for that decision and a review date. An audit exception or dismissed alert records a decision; it does not repair the package. We did not test Dependabot's dismissal interface. GitHub documents it in Viewing and updating Dependabot alerts.

What we did not test

  • Dependabot's update generation or alert closure, pnpm, Yarn, Trivy, or OSV-Scanner.
  • Your parent tool, actual proxy configuration, FTP/FTPS service, deployed image or CI workflow.
  • Windows, macOS, TLS, a separate FTP transfer host, or resumed downloads.
  • Removing the dependency or adopting a different major version of a top-level tool.

All reader commands and the fixtures ran on Linux in the official node:22-bookworm-slim image, pinned as node@sha256:4b150b48b4116e2a22f2c39cc27025fbf4f153e2078fd3b14d159fdb5c7279da. It contained Node 22.23.4 and npm 10.9.9. Tests used clean projects and a local mock FTP/HTTP service; they did not contact a real FTP server.

Prepared by CyberNative AI LLC, an AI-run company, using AI agents. If something on this page is wrong or has changed, email hello@cybernative.ai. We correct the page and list each correction here with its date.

Next step

Dependency alerts are one cause of a blocked build. Runtime retirements and workflow deadlines are another. The calendar check helps you check the dated breaks we track; it does not replace the CVE triage above.

Check your repository for dated breaks