# cargo-deny: four dependency checks for Rust workspaces

> cargo-deny is a Cargo subcommand that lints the dependency graph for licences, banned crates, advisories and untrusted sources. It is a policy gate, not a vulnerability scanner, and the README is explicit that nothing it prints is legal advice.

**EmbarkStudios/cargo-deny** — ❌ Cargo plugin for linting your dependencies 🦀

- Repository: https://github.com/EmbarkStudios/cargo-deny
- Website: http://embark.rs
- Stars: 2,436 · Forks: 134
- Language: Rust
- License: Apache-2.0
- Published: 2026-09-28 · Updated: 2026-09-28 · Language: en
- Canonical page: https://hysenlabs.com/projects/embarkstudios-cargo-deny

## The dependency review problem cargo-deny targets

A Rust workspace resolves a graph, not a list. A single application can pull hundreds of transitive crates, each with its own licence expression, its own version, and its own registry origin. Reviewing that by hand does not scale, and the failures are quiet: two versions of the same crate compiled into one binary, a copyleft licence arriving three levels down, a crate published from a git source nobody vetted.

cargo-deny is aimed at the person who has to answer for that graph. The README describes it as a Cargo plugin for linting dependencies, and the four checks split the problem into policy questions a team can actually decide: which licences are acceptable, which crates are banned or duplicated, which advisories apply, and which sources are trusted. The audience is maintainers of larger Rust codebases and anyone who has to produce a dependency inventory for a release. It is not a general-purpose security scanner, and the README states plainly that the tool comes with no responsibility for whether it functions correctly or meets your needs.

## Four checks, one configuration file

The mechanism is straightforward. cargo-deny reads Cargo metadata for the workspace, builds a graph with the krates crate, and runs each check against that graph. Output is rendered through codespan-reporting, which is why the README's screenshots show diagnostics with source spans rather than plain lines of text.

The checks are separate subcommands, so you can adopt one without the others. licenses verifies that every crate carries licence terms you accept. bans denies or allows specific crates and detects multiple versions of the same crate. advisories looks up crates in an advisory database. sources restricts crates to origins you trust. Each has its own section in the project's book, and the repository ships an examples directory with one folder per scenario, including 01_allow_license, 02_deny_license, 06_advisories, 07_deny_sources, 09_bans, 11_feature_bans, 12_yank_check and 13_license_clarification. Those directory names are the clearest signal of the intended granularity: a ban can target a feature, not just a crate name.

Configuration lives in deny.toml, and the repository carries both a deny.toml for its own build and a deny.template.toml. The SPDX badge in the README points at SPDX 3.25.0, which is the licence list the licences check matches against.

## Installing cargo-deny and running your first check

The README gives a three-command quickstart. Install the binary from crates.io, initialise a config in the current project, then run the full check.

```bash
cargo install --locked cargo-deny && cargo deny init && cargo deny check
```

The --locked flag is not decoration. It makes cargo install resolve against the published lockfile rather than the newest compatible versions, which is the difference between a reproducible install and a surprise. After init you should have a deny.toml in the project root; after check you should see diagnostics grouped by which check produced them.

Arch users have a packaged route instead of building from source:

```bash
pacman -S cargo-deny
```

If you want the binary without a Cargo toolchain present, for example inside a slim container image, the README says to build with the standalone feature. That is the documented reason the feature exists, and it is the only install variant the README calls out for Docker.

Individual checks run on their own, which is how most people start, because a full check against an unconfigured workspace will produce a wall of findings:

```bash
cargo deny check licenses
```

The same pattern applies to bans, advisories and sources. Once the config is tuned, the pre-commit integration is a YAML block in .pre-commit-config.yaml pointing at the repository with a rev and the cargo-deny hook id, with args defaulting to --all-features check.

## Where cargo-deny stops being the right tool

The licences check matches licence expressions. It does not read your source, and it does not resolve the question of whether a given licence is compatible with how you ship your binary. The README says this directly: no functionality in, or information provided by, cargo-deny constitutes legal advice. A green licences check is a statement about metadata, not about your obligations.

There is a second boundary around advisories. The check looks issues up in an advisory database, which means its coverage is exactly the coverage of that database. A crate with a known problem that no advisory has been filed for will pass. Teams that read cargo-deny as a substitute for a vulnerability scanner are reading it wrong; it is a policy gate that happens to include one advisory check.

Offline and air-gapped builds are a practical constraint worth checking before you commit. The related search terms around offline use suggest people hit it, and the repository has a supply-chain directory plus a .cargo directory, but the README as given does not spell out an offline workflow, so treat that as something to verify against the book rather than assume.

The last push to the repository was on 2026-09-18, and the most recent release listed is 0.20.2 from 2026-07-09. Note that the Cargo manifest declares a badge with maintenance status actively-developed while the README pins a minimum stable Rust version of 1.88.0 and the package uses edition 2024. That is a real constraint: if your toolchain is older than 1.88.0, the current release will not build.

## cargo-deny compared with cargo-audit and cargo-about

The comparison people search for is cargo deny versus cargo audit, and the difference is scope rather than quality. cargo-audit is a vulnerability checker: it queries the RustSec advisory database and reports affected crates. cargo-deny's advisories check overlaps with that, but advisories are one of four checks, and the other three have nothing to do with vulnerabilities. If your only question is which crates have open advisories, cargo-audit is the narrower instrument and the one that answers only that question.

cargo-about solves a different adjacent problem. It generates a licence listing, typically for attribution pages or a NOTICE file. cargo-deny's licences check does not produce that artefact; it decides whether each licence in the graph is one you accept. Teams often end up running cargo-about to publish attributions and cargo-deny to enforce the allowlist, because generating a document and failing a build are different jobs.

The practical difference in approach is that cargo-deny is configuration-first. Its value comes from deny.toml encoding decisions your team has made, including exceptions. Run it with a default config and you get noise; run it with a tuned config and it becomes a gate. That is the opposite of a scanner you point at a repository and read.

## Maintenance, upgrades and licence terms

The project is not archived, and the last push was on 2026-09-18. Releases in the recent window are 0.20.2 on 2026-07-09, 0.19.9 on 2026-06-15 and 0.19.8 on 2026-05-28. There is a CHANGELOG.md at the repository root, which is where upgrade cost actually lives: the checks are configuration-driven, so a version bump can change how an existing deny.toml is interpreted. Read the changelog before moving a pinned rev in CI, particularly if you pin the pre-commit rev or a GitHub Action version.

On licensing, the README states the project is dual licensed under Apache-2.0 and MIT, at your option, and the repository carries LICENSE-APACHE and LICENSE-MIT. The Cargo manifest declares license = "MIT OR Apache-2.0", consistent with the README. Contributions are dual licensed under the same terms unless stated otherwise. That covers the tool itself. It says nothing about the licences of the crates in your own graph, which is a separate question the licences check is designed to surface, and the README's disclaimer about legal advice applies to that surface too.

## Conclusion

Adopt cargo-deny if your Rust project has a dependency graph large enough that licence and duplicate-version drift is a real review burden: the four checks map cleanly onto CI, and the pre-commit hook and cargo-deny-action both exist. Skip it if what you actually want is a vulnerability feed for a single application, since advisories are one check among four and the tool is a policy gate rather than a scanner. Before wiring it into a required pipeline, run cargo deny check against your own workspace and count how many findings are genuine versus how many need an exception in deny.toml; that ratio, not the README, decides whether the gate is worth enforcing.

## FAQ

### How do I install cargo-deny?

The README's quickstart is cargo install --locked cargo-deny. Arch users can install the packaged version with pacman -S cargo-deny, and building with the standalone feature is documented for use without a Cargo toolchain, for example in Docker images.

### What does cargo deny do?

It lints a Rust workspace's dependency graph through four checks: licenses verifies accepted licence terms, bans denies or allows specific crates and detects duplicate versions, advisories looks crates up in an advisory database, and sources restricts crates to trusted origins.

### How do I use cargo deny?

Run cargo deny init to create a deny.toml in the project, then cargo deny check to run every check, or a single check such as cargo deny check licenses. The README also documents a pre-commit hook with the cargo-deny hook id and default args of --all-features check.

### What is the difference between cargo deny and cargo audit?

cargo-deny's advisories check overlaps with cargo-audit's vulnerability lookup, but advisories are only one of cargo-deny's four checks. The licences, bans and sources checks have no equivalent in a pure vulnerability scanner.

### What is cargo deny?

It is a Cargo plugin from EmbarkStudios for linting dependencies, described in the README as a tool to help you manage large dependency graphs. It ships as the cargo-deny binary and is configured through deny.toml.

## Sources

- [EmbarkStudios/cargo-deny on GitHub](https://github.com/EmbarkStudios/cargo-deny)
- [License: Apache-2.0](https://github.com/EmbarkStudios/cargo-deny/blob/main/LICENSE)
- [Project website](http://embark.rs)
- [README](https://github.com/EmbarkStudios/cargo-deny/blob/main/README.md)
- [Releases](https://github.com/EmbarkStudios/cargo-deny/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/embarkstudios-cargo-deny
