ITADN

cargo 1.96.0 regression for `registry+https` URLs in index dependency entries

#17096Openmaxdymond 创建于 2026-06-12
C-bugA-registriesS-triage
M
maxdymondcommented
### Problem The CVE-2026-5222 fix (PR #17031) changed `CanonicalUrl::new()` to skip github.com URL canonicalization when the scheme contains `+`. This broke tolerance of `registry+https://` URLs in the `"registry"` field of index dependency entries - a format that was never correct per the spec, but that some registry implementations (notably JFrog Artifactory) emit. These URLs are no longer canonicalized to match their plain `https://` counterparts, so cargo treats them as a separate unknown source instead of recognizing them as crates-io. While I don't necessarily think the onus is on [Cargo](https://xkcd.com/1172/) to fix this, it would be nice if we didn't have to pin 1.95.0 forever. ### Background The CVE-2026-5222 fix (commit `c4d63a442`, merged in PR [#17031](https://github.com/rust-lang/cargo/pull/17031)) added a guard to `CanonicalUrl::new()` in `src/cargo/util/canonical_url.rs`: ```rust // Before (1.95): if url.host_str() == Some("github.com") { url = format!("https{}", &url[url::Position::AfterScheme..]).parse().unwrap(); // ... } // After (1.96): if !url.scheme().contains('+') { // <-- new guard if url.host_str() == Some("github.com") { url = format!("https{}", &url[url::Position::AfterScheme..]).parse().unwrap(); // ... } } ``` In 1.95: `CanonicalUrl::new()` canonicalized `registry+https://github.com/rust-lang/crates.io-index` by detecting `github.com` as the host and rewriting the scheme to `https`. This produced the same canonical URL as the correct crates-io `SourceId` (`https://github.com/rust-lang/crates.io-index`). Since `SourceId` equality is based on `(kind, canonical_url, precise)`, the bad SourceId was interned to the same value as the real crates-io one and everything worked. In 1.96: The `!url.scheme().contains('+')` guard skips canonicalization for URLs with `+` in the scheme (intended to protect sparse registries), but this also skips canonicalization for the bogus `registry+https://...` URL. The canonical URL remains `registry+https://github.com/rust-lang/crates.io-index`, which does not match the real crates-io canonical URL. The `id2name` HashMap lookup in `SourceConfigMap::load()` fails, `replace-with` is never applied, and cargo falls through to trying to git-fetch the raw URL - which fails because `registry+https` is not a valid git remote scheme. ### Steps Have a JFrog Artifactory sparse registry, and use cargo 1.96.0. ### Possible Solution(s) _No response_ ### Notes I confirmed this by adding `eprintln!` diagnostics to `registry_dependency_into_dep()`, `ensure_loaded()`, `SourceConfigMap::load()`, and `CanonicalUrl::new()` in both versions: 1.95 (pre-CVE fix): ``` registry_dep_into_dep: name=anyhow, raw_registry="registry+https://github.com/rust-lang/crates.io-index", source_id=registry `crates-io` <= bogus URL canonicalized to match crates-io ensure_loaded: namespace=registry `crates-io` <= correct, replace-with applied ``` 1.96 (post-CVE fix): ``` CanonicalUrl::new: input=registry+https://github.com/rust-lang/crates.io-index, canonical=registry+https://github.com/rust-lang/crates.io-index <= not canonicalized registry_dep_into_dep: name=anyhow, raw_registry="registry+https://github.com/rust-lang/crates.io-index", source_id=registry `registry+https://github.com/rust-lang/crates.io-index` <= bogus ensure_loaded: namespace=registry `registry+https://...` SourceConfigMap::load: NOT FOUND in id2name <= replace-with never applied ``` ### Version ```text cargo 1.96.0 (30a34c682 2026-05-25) release: 1.96.0 commit-hash: 30a34c6821b57de0aaec83a901aca39f88f6778c commit-date: 2026-05-25 host: x86_64-unknown-linux-gnu libgit2: 1.9.2 (sys:0.20.4 vendored) libcurl: 8.19.0-DEV (sys:0.4.87+curl-8.19.0 vendored ssl:OpenSSL/3.5.4) ssl: OpenSSL 3.5.4 30 Sep 2025 os: Red Hat Enterprise Linux 9.8.0 [64-bit] ```
1 条评论