Safeguard
Open Source

npm ssh2-sftp-client: Security Review and Safe Usage

ssh2-sftp-client wraps the ssh2 library in a promise-based SFTP API. Its security posture rests on host key verification and credential handling, which are easy to get wrong.

Priya Mehta
DevSecOps Engineer
5 min read

The npm ssh2-sftp-client package is a promise-based wrapper around the ssh2 library that gives you a clean async API for SFTP file transfers, and its security depends almost entirely on two things you configure yourself: verifying the server's host key and handling credentials safely. The library itself is a thin, well-scoped convenience layer. The mistakes that turn an SFTP client into a liability are configuration mistakes, and they are common enough to be worth walking through.

SFTP runs over SSH, so every SSH security concern applies. The difference from using raw ssh2 npm is ergonomics: ssh2-sftp-client hides the connection lifecycle and exposes get, put, list, and friends as promises. That convenience is why so many Node teams reach for it over lower-level npm sftp options.

The host key verification gap

Here is the single most important thing about using this library safely. By default, connecting without checking the server's host key leaves you open to a man-in-the-middle attack. An attacker who can intercept the connection presents their own host key, you connect anyway, and they proxy your credentials and files.

ssh2-sftp-client passes connection options straight through to ssh2, which exposes a hostVerifier callback for exactly this. Use it:

const Client = require('ssh2-sftp-client');
const crypto = require('crypto');

const KNOWN_FINGERPRINT = process.env.SFTP_HOST_FINGERPRINT;

const sftp = new Client();
await sftp.connect({
  host: 'files.example.com',
  port: 22,
  username: process.env.SFTP_USER,
  privateKey: process.env.SFTP_PRIVATE_KEY,
  hostVerifier: (hashedKey) => {
    const fingerprint = crypto
      .createHash('sha256')
      .update(hashedKey)
      .digest('base64');
    return fingerprint === KNOWN_FINGERPRINT;
  },
});

Pin the expected fingerprint out of band, the same way you would trust an SSH host key on first use in a terminal, and reject anything else. Skipping hostVerifier is the equivalent of blindly typing "yes" to every SSH host key prompt, in an automated process that will never notice something changed.

Credentials: keys over passwords

The connect options accept either a password or a private key. Prefer key-based authentication. Passwords in configuration are easy to leak in logs, error dumps, and process listings; a private key referenced from a secrets manager and loaded at runtime is easier to rotate and to keep out of source control.

Two rules regardless of method:

  • Never hardcode credentials. Pull them from environment variables backed by a secrets manager, as in the snippet above.
  • Scrub connection errors before logging. ssh2 errors can echo back parts of the configuration, and a careless console.log(err) on a connection failure can print a key path or worse.

The relationship to the ssh2 library

ssh2-sftp-client does not implement the SSH protocol; ssh2 does. That means your actual cryptographic and protocol-level trust sits with the ssh2 npm package underneath. When you audit this dependency, audit ssh2 too, because that is where a protocol-level vulnerability would live. Keep both current, and treat a security release in ssh2 as something to apply promptly even if the wrapper has not published a new version.

This layering is also why you should not pin ssh2-sftp-client so rigidly that it holds back a patched ssh2. Pin the wrapper's exact version for reproducibility, but make sure your lockfile resolves ssh2 to a version that includes any relevant fixes. Verify any specific advisory against the ssh2 GitHub security advisories or the npm registry before acting on a claim about a particular version, rather than assuming a version is affected. An SCA tool automates that check across both packages and tells you when a fixed version exists.

Operational hardening

Beyond the client configuration, a few habits reduce blast radius:

  1. Least privilege on the remote account. The SFTP user should be chrooted or restricted to the directories it needs. If the client is ever compromised, you do not want it holding shell access.
  2. Validate remote paths. If any part of a get or put path comes from user input, sanitize it. Path traversal in a file transfer can read or overwrite unintended files on the server.
  3. Set timeouts and close connections. Use readyTimeout and always sftp.end() in a finally block. Leaked connections are both a reliability and a resource-exhaustion concern.
  4. Verify file integrity. For sensitive transfers, checksum the file after transfer to detect truncation or tampering.

A safe usage summary

Put together, using npm ssh2-sftp-client safely comes down to: always set hostVerifier, authenticate with keys pulled from a secrets manager, keep the underlying ssh2 library patched, restrict the remote account, and sanitize any path derived from input. The library gives you a pleasant API; the security is what you configure around it.

FAQ

What is the most important security setting in ssh2-sftp-client?

The hostVerifier callback. Without it, the client accepts any server host key, which exposes the connection to man-in-the-middle attacks. Pin the expected fingerprint and reject anything that does not match.

Should I use a password or a private key with ssh2-sftp-client?

Prefer a private key loaded from a secrets manager. Passwords are more likely to leak through logs and process listings and are harder to rotate cleanly.

Do I need to audit the ssh2 library separately?

Yes. ssh2-sftp-client is a wrapper; the SSH protocol and cryptography live in the ssh2 package underneath. Protocol-level vulnerabilities appear there, so keep ssh2 patched and include it in your dependency scans.

How do I prevent path traversal in SFTP transfers?

Sanitize any remote path that includes user-controlled input before passing it to get or put, and restrict the remote SFTP account to the directories it actually needs so a bad path cannot escape its intended scope.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.