Cargo's SSH fix restores verification of the repository server
Rust 1.66.1 fixes Cargo's missing SSH host-key verification. The advisory also identifies Git URL rewrites that can make an apparently HTTPS-based dependency workflow use the affected transport.
Authenticating to a repository server does not establish that the server is the intended one. An SSH connection needs to verify the server's host key as well. Cargo's built-in Git support omitted that verification when cloning dependencies and registry indexes over SSH. The January 10 advisory identifies the resulting man-in-the-middle exposure as CVE-2022-46176.
The Rust project releases Rust 1.66.1 to correct the omission. According to the advisory, all Rust versions containing Cargo before that release are affected. The fix changes the connection contract, because an SSH server must now present a host key Cargo already trusts before the operation can continue.
I find Rust's explicit semantics compelling, especially when considering work that might otherwise require C. Dependency acquisition remains outside the guarantees supplied by the language's type system. A compiler can faithfully build the source it receives while the transport that supplied that source failed to authenticate its origin.
Client identity and server identity solve different problems
SSH host-key verification checks the identity of the remote endpoint. The advisory describes comparing the server's public key with a previously trusted key and aborting when the key changes. Without that check, a client can establish an encrypted connection without establishing that it has reached the expected server.
That distinction explains the man-in-the-middle risk. Encryption alone does not identify the party at the other end of the encrypted session. A build that obtains an index or dependency from an impersonating endpoint can consume content under a false assumption about its source. The advisory identifies the missing verification as the defect, rather than a weakness in Rust's memory model.
The Cargo authentication documentation at the patched version describes SSH authentication through an agent separately from known-host verification. An agent supplies a client key. Known-host information identifies acceptable server keys. Having the first configured does not replace the second.
A successful connection before this fix consequently provided less assurance than users could reasonably expect from SSH. The absence of a host-key error was not evidence that Cargo had compared the remote key against trusted state. It had not implemented the relevant check at all, according to the advisory.
URL rewriting can change which transport Cargo uses
The disclosure warns that affected users may not explicitly name an SSH dependency. Git's url.<base>.insteadOf setting can replace HTTPS connections to GitHub with SSH. Under that configuration, an index that appears to use HTTPS can be cloned over the affected SSH path.
This makes effective configuration more important than the URL visible in one manifest. A global Git rule can change how the dependency operation reaches the network. Assessing exposure requires following that rewrite to the transport actually used by Cargo, rather than assuming that the initial URL settles the question.
The advisory specifically includes registry indexes as well as dependencies. Those are separate inputs to dependency resolution and fetching. A project may have no direct Git dependency while still encountering SSH through the index transport after rewriting. The relevant scope is broader than searching dependency declarations for strings beginning with ssh.
This is a useful detail because transport configuration often exists outside an individual project. A developer can carry the same Git rewrite across many repositories. An automated environment can also inherit configuration whose effect is not apparent in the source tree being built. The dependency workflow includes that configuration even when the manifest remains unchanged.
Unknown keys now stop the operation
Rust 1.66.1 changes Cargo to abort when an SSH server's public key is not already trusted. The advisory explicitly says Cargo will not ask interactively whether to trust the key on a first connection. It instead returns an error explaining how to add the key to trusted configuration.
That is a visible behavior change for automation. A build that previously fetched from an unrecognized host without complaint may now fail until trusted host-key information is supplied. The failure means the new verification requirement has encountered missing trust state. Removing the check would reinstate the condition the security release is intended to correct.
The versioned documentation lists OpenSSH-style known-host files as a source of trust, including the user's .ssh/known_hosts and platform-specific system locations. Cargo configuration can also supply keys through net.ssh.known-hosts. These mechanisms make the expected server key an explicit input to the fetch operation.
The documentation also explains fingerprints as compact hashes suitable for verification against information supplied by the server administrator or a published source. Receiving a fingerprint from the connection does not independently authenticate it. The useful comparison is with an expected fingerprint learned through a trusted route.
I prefer that an unattended build fail on missing server trust rather than quietly treat a newly observed key as authoritative. The error makes a missing prerequisite visible at the point of acquisition. It also gives automation a defined configuration responsibility instead of relying on an interactive prompt that a job cannot answer responsibly.
The patched documentation says Cargo includes GitHub's host keys. That is a built-in trust choice for a well-known service, alongside the ability to add keys in configuration. It does not imply that Cargo can accept every private repository host without prior setup. Other endpoints still need an expected key available to the verifier.
Delegating Git is an explicit mitigation
For users unable to upgrade immediately, the advisory recommends Cargo's external Git mode. The configuration switches Git network operations from the built-in implementation to the Git command-line client, which the advisory says is unaffected by this vulnerability.
[net]
git-fetch-with-cli = true
This is a change in the implementation performing the fetch. It is not a declaration that server verification is unnecessary. The external client brings its own SSH behavior and configuration into the operation. The mitigation works by using that unaffected client for the network path.
The Cargo documentation gives another practical distinction between the implementations. The built-in SSH library does not use OpenSSH's ~/.ssh/config. More advanced SSH requirements should use the external Git mode. A successful command-line SSH test therefore does not prove that Cargo's built-in path will use every setting from that test.
That difference matters when diagnosing a fetch failure after the patch. The expected key and connection settings need to be available to the implementation actually running. Cargo's configuration and OpenSSH's configuration overlap in purpose, but they are not interchangeable inputs to every code path.
The external mode can also be enabled through CARGO_NET_GIT_FETCH_WITH_CLI=true, as documented for this version. This gives an automated environment a way to select the mitigation without adding a project-specific setting. The chosen route should remain visible in the build environment's configuration because it determines which network implementation and authentication behavior the operation uses.
The mitigation and the upgrade also have different scopes. Selecting external Git changes which client performs subsequent network operations. Upgrading changes Cargo itself so that its built-in SSH path verifies keys. Both are prospective corrections to acquisition behavior. Neither statement establishes what endpoint supplied a dependency during an earlier fetch. That historical question depends on the transport and configuration in effect at the time.
For a private repository host, the newly enforced check can reveal missing provisioning in a build image. The job may have credentials to identify its account but no record of the server key it expects. Supplying client credentials alone leaves that second input absent, which is why a previously successful fetch can stop after the security update.
Source safety depends on acquisition as well as compilation
The advisory credits the Julia Security Team for disclosure and identifies the Rust contributors who wrote and reviewed the correction. It also supplies patch files for custom toolchains based on Rust 1.66.0. These are specific remediation paths for the disclosed implementation failure, alongside the patched stable release and external-client mitigation.
The correction does not require application code to change its use of ownership or borrowing. It changes the assurance available before that code is compiled. The server supplying an SSH dependency or index must now satisfy a host-key check that Cargo previously omitted.
My interest in Rust includes the way it makes low-level obligations explicit. This incident places an equally concrete obligation on the toolchain's input path. The dependency build begins with a claim about where source came from, and the patched Cargo verifies the SSH endpoint against trusted keys before accepting that connection.