Skip to content
rusthacks.dev
Security

Checking Licenses and Bans With Cargo Deny Config Explained

cargo-deny checks advisories, licenses, banned crates and registry sources from one deny.toml. See a working configuration, how to read failures and how to add exceptions with a reason.

2 min read
Summarize in AI
Flat illustration for the post “Checking Licenses and Bans With Cargo Deny Config Explained”, composed around security.

A pull request adds a convenient crate. It pulls in forty others, one of them under a license your company's lawyers have not approved and another with a published advisory. Nobody reads the lock file diff, so it merges. cargo-deny is the gate that reads it for you. This post gives a working deny.toml and explains each section. It is the policy half of dependency risk in Rust, and a component of the security baseline.

cargo-deny 0.16, Rust 1.90.

Start

Shell
cargo install cargo-deny --locked
cargo deny init
cargo deny check

init writes a commented deny.toml with the defaults. The sections below show the parts worth setting.

A practical configuration

deny.tomlTOML
[advisories]
version = 2
yanked = "deny"
ignore = [
    # { id = "RUSTSEC-YYYY-NNNN", reason = "not reachable: we never call the affected parser" },
]

[licenses]
version = 2
allow = [
    "MIT",
    "Apache-2.0",
    "Apache-2.0 WITH LLVM-exception",
    "BSD-2-Clause",
    "BSD-3-Clause",
    "ISC",
    "Unicode-3.0",
]
confidence-threshold = 0.9

[bans]
multiple-versions = "warn"
wildcards = "deny"
deny = [
    { crate = "openssl", reason = "we use rustls; avoids a C dependency" },
]

[sources]
unknown-registry = "deny"
unknown-git = "deny"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]

advisories

Reads the RustSec database. yanked = "deny" fails on withdrawn versions. Vulnerabilities and unsound code are errors by default, so do not allow them silently. Each ignore must say why; "not reachable" needs a reviewer who can confirm it.

licenses

An explicit allow list. When a new dependency has GPL-3.0 or MPL-2.0 and you have not approved it, the check fails and names the crate:

Text
error[rejected]: failed to satisfy license requirements
   ┌─ some-crate 1.2.3
   │ license = "GPL-3.0"
   │ rejected: license is not explicitly allowed

You then decide: pick another crate, ask legal, or add the license. Dual licensed crates (MIT OR Apache-2.0) pass if one side is allowed.

bans

multiple-versions = "warn" lists crates that appear twice at different versions, which bloats builds and sometimes signals an out-of-date dependency. wildcards = "deny" rejects * version requirements. The deny list bans specific crates with a reason that appears in the failure.

sources

Only allow crates.io (the sparse protocol URL is used by default; check what init generated for your Cargo version). Git dependencies get through only if listed in allow-git.

In CI

YAML
- uses: EmbarkStudios/cargo-deny-action@v2

or cargo deny check after installing. Run the advisories check on a schedule as well, since new advisories appear for unchanged code (GitHub Actions for Rust).

Exceptions

Put them in the file, not in a comment in a pull request. A dated reason lets you remove the ignore when the upstream fix lands.

Limits

It knows the database and the metadata, and nothing about your code's reachability. Licenses declared in crate metadata can be wrong. For reviewing the actual source of dependencies, see cargo vet. The tool's book is at embarkstudios.github.io/cargo-deny.

Share

Keep reading

Flat illustration for the post “Request Limits and Slow Client Attacks in Rust Services”, composed around web.
Security

Request Limits and Slow Client Attacks in Rust Services

Slow clients and oversized requests exhaust connections and memory. Set header and body timeouts, body size limits, concurrency limits and keep-alive bounds at the proxy and in the Axum service with Tower layers.

5 min read

Get new posts by email

We send one email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.