Use the [bans] table in deny.toml: list unwanted crates under deny, set multiple-versions to flag duplicates, and set wildcards to catch star version requirements. Defaults for the last two are warn. Use skip for known duplicates, with a reason on each.
The keys
| Key | Purpose | Default |
|---|---|---|
multiple-versions | What to do when two versions of one crate are in the graph | warn |
wildcards | What to do for dependencies using a star version | warn |
deny | Crates you never want, with optional reason and replacement | none |
skip | Ignore a crate during duplicate detection | none |
skip-tree | Skip a crate and everything below it | depth unlimited |
The documentation calls skip-tree a very big hammer, and it is. Prefer skip entries one crate at a time.
Why duplicates matter for security
Two versions of the same crate means two copies of its code in your binary, and a fix in one may leave the other exposed. When an advisory lands, you have to patch both, and the older copy is often held there by one stubborn parent crate. Duplicates also add build time and binary size, as the Cargo documentation notes for its duplicates view.
Finding the cause before banning
Run cargo tree -d to list crates that appear in more than one version. Then use the inverted view, for example cargo tree -i crate_name, to see which parent pulls in each copy. Often one update of one parent removes the duplicate.
Banning a crate
[bans]
multiple-versions = "warn"
wildcards = "deny"
deny = [
{ crate = "openssl", reason = "we standardise on one TLS stack", use-instead = "rustls" },
]
The names here are examples of the config shape, not a recommendation about any crate. Pick bans from your own policy, such as a TLS stack decision or a crate your legal team rejected.
Wildcards
A bare star requirement lets any version satisfy the dependency. crates.io does not allow bare star versions on published crates, according to the Cargo reference, but they can appear in path or git dependencies inside a workspace. Denying wildcards keeps version intent explicit.
Rollout steps
- Run the check with warn and capture the baseline.
- Fix the cheap duplicates with a conservative update.
- Add
skipentries, each with a reason, for the rest. - Add real bans from policy.
- Move wildcards to deny, and consider multiple versions at deny once the list is short.
Quick check
Should multiple-versions be deny from day one?
Usually no. Large graphs have legitimate duplicates, so start at warn and shrink the list.
What is the difference between skip and skip-tree?
Skip ignores one crate in duplicate detection. Skip-tree also ignores its transitive dependencies, so it hides much more.
Safeguard SBOM and dependency scanning shows the full set of versions in your graph, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.