# How to Verify Dependencies with Hashes in uv


Dependency hashes let [uv](https://pydevtools.com/handbook/reference/uv.md) verify that every downloaded artifact matches what was resolved, catching tampering before anything gets installed.

## Hashes in uv.lock

`uv.lock` includes SHA-256 hashes for every distribution by default. After running `uv lock` or `uv add`, each entry in the lockfile contains hashes for both sdists and wheels:

```toml
[[package]]
name = "certifi"
version = "2026.2.25"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "...", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7" }
wheels = [
    { url = "...", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa" },
]
```

When `uv sync` or `uv run` installs packages, it checks each downloaded artifact against these hashes. If a hash does not match, installation fails.

## Hashes in requirements.txt

Some deployment workflows use `requirements.txt` instead of `uv.lock`. Two commands produce requirements files with hashes.

`uv pip compile` with the `--generate-hashes` flag:

```bash
uv pip compile pyproject.toml --generate-hashes -o requirements.txt
```

This produces output like:

```text
certifi==2026.2.25 \
    --hash=sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa \
    --hash=sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7
```

`uv export` includes hashes by default:

```bash
uv export -o requirements.txt
```

To omit hashes, pass `--no-hashes`.

## What hashes protect against

Hash verification guards against artifacts that have been altered after resolution. This covers tampering in transit (man-in-the-middle attacks) and corrupted or malicious mirrors and caches.

> [!IMPORTANT]
> Hashes do **not** protect against a malicious package uploaded directly to PyPI. If an attacker publishes a compromised version through legitimate channels, the hashes will match because they were generated from the compromised artifact itself. For that threat, consider using [`--exclude-newer`](https://pydevtools.com/handbook/how-to/how-to-protect-against-python-supply-chain-attacks-with-uv.md) to avoid installing recently published versions.

Hash pinning works best alongside other supply-chain protections. A [lockfile](https://pydevtools.com/handbook/how-to/how-to-use-a-uv-lockfile-for-reproducible-python-environments.md) pins exact versions, while [dependency cooldowns](https://pydevtools.com/handbook/how-to/how-to-protect-against-python-supply-chain-attacks-with-uv.md) add a time-based filter against recently published packages.

## Learn more

- [uv: A Complete Guide](https://pydevtools.com/handbook/explanation/uv-complete-guide.md) covers what uv does, how fast it is, the core workflows, and recent releases.
