Make uv’s first-index strategy more secure by default by failing early on authentication failure (#12805)

uv’s default index strategy was designed with dependency confusion
attacks in mind. [According to the
docs](https://docs.astral.sh/uv/configuration/indexes/#searching-across-multiple-indexes),
“if a package exists on an internal index, it should always be installed
from the internal index, and never from PyPI”. Unfortunately, this is
not true in the case where authentication fails on that internal index.
In that case, uv will simply try the next index (even on the
`first-index` strategy). This means that uv is not secure by default in
this common scenario.

This PR causes uv to stop searching for a package if it encounters an
authentication failure at an index. It is possible to opt out of this
behavior for an index with a new `pyproject.toml` option
`ignore-error-codes`. For example:

```
[[tool.uv.index]]
name = "my-index"
url = "<index-url>"
ignore-error-codes = [401, 403]
```

This will also enable users to handle idiosyncratic registries in a more
fine-grained way. For example, PyTorch registries return a 403 when a
package is not found. In this PR, we special-case PyTorch registries to
ignore 403s, but users can use `ignore-error-codes` to handle similar
behaviors if they encounter them on internal registries.

Depends on #12651

Closes #9429
Closes #12362
This commit is contained in:
Zanie Blue 2025-04-29 12:57:19 -05:00
parent 11d00d21f7
commit f84faf726a
16 changed files with 784 additions and 99 deletions

View file

@ -122,7 +122,7 @@ malicious package to be installed instead of the internal package. See, for exam
[the `torchtriton` attack](https://pytorch.org/blog/compromised-nightly-dependency/) from
December 2022.
Users can opt in to alternate index behaviors via the`--index-strategy` command-line option, or the
To opt in to alternate index behaviors, use the`--index-strategy` command-line option, or the
`UV_INDEX_STRATEGY` environment variable, which supports the following values:
- `first-index` (default): Search for each package across all indexes, limiting the candidate
@ -211,6 +211,27 @@ credentials cannot be found. If the discovered credentials are not valid (i.e.,
HTTP 401 or 403), then uv will treat packages as unavailable and query the next configured index as
described in the [index strategy](#searching-across-multiple-indexes) section.
### Ignoring error codes when searching across indexes
When using the [first-index strategy](#searching-across-multiple-indexes), uv will stop searching
across indexes if an HTTP 401 Unauthorized or HTTP 403 Forbidden status code is encountered. The one
exception is that uv will ignore 403s when searching the `pytorch` index (since this index returns a
403 when a package is not present).
To configure which error codes are ignored for an index, use the `ignored-error-codes` setting. For
example, to ignore 403s (but not 401s) for a private index:
```toml
[[tool.uv.index]]
name = "private-index"
url = "https://private-index.com/simple"
authenticate = "always"
ignore-error-codes = [403]
```
uv will always continue searching across indexes when it encounters a `404 Not Found`. This cannot
be overridden.
### Disabling authentication
To prevent leaking credentials, authentication can be disabled for an index: