Skip to content
rusthacks.dev
Security

Dependency Risk in Rust and Reading Advisories Explained

Every crate you add runs with your privileges, and build scripts and proc macros run at compile time. Learn how advisories work, how to read a RustSec entry and how to limit the surface.

3 min read
Summarize in AI
Flat illustration for the post “Dependency Risk in Rust and Reading Advisories Explained”, composed around security.

A typical web service pulls in 200 or more crates, and you have read the code of none of them. That is a normal state of affairs and a fact to manage, not a reason for alarm. The tools make it tractable: an advisory database, a scanner and a few habits. This post shows how to read what the scanner says and how to keep the tree small. It continues the threat model in security for Rust developers.

cargo-audit 0.21, cargo-deny 0.16, Rust 1.90.

Run the scanner

Shell
cargo install cargo-audit --locked
cargo audit

A finding has this shape (the crate name and identifiers here are placeholders):

Text
Crate:     example-crate
Version:   0.4.1
Title:     Out-of-bounds read in parse_header
Date:      YYYY-MM-DD
ID:        RUSTSEC-YYYY-NNNN
URL:       https://rustsec.org/advisories/RUSTSEC-YYYY-NNNN
Solution:  Upgrade to >=0.4.2
Dependency tree:
example-crate 0.4.1
└── my-service 0.1.0

The ID links to the advisory. Read the description before reacting: does your code reach the vulnerable function? Many advisories apply only to specific features. The dependency tree shows who pulled it in, which matters if the fix is a transitive update. cargo update -p example-crate bumps it within semver, and a major bump of a parent may be needed.

Kinds of advisory

KindMeaningResponse
Vulnerabilityexploitable flaw with a patched versionupgrade, or mitigate if no patch exists
Unmaintainedno active maintainerplan a replacement; not urgent unless exposed
Unsoundsafe API that can cause undefined behaviorupgrade or avoid the API
Yankedversion withdrawn by the authormove off it; cargo update shows the warning

Where code runs

Compiling a project executes code from dependencies: build.rs scripts run as your user, and procedural macros run inside the compiler. A malicious crate does not need to be called at run time to do harm. Mitigations: build in a container or CI sandbox without secrets, review changes in Cargo.lock diffs in pull requests (new crates stand out), and consider cargo vet to record audits by people you trust.

Keeping the tree small

Shell
cargo tree --depth 1       # direct dependencies
cargo tree -d              # duplicate versions
cargo tree -i openssl-sys  # what pulls this in?

Questions to ask before adding a crate:

  1. Can the standard library do this in 20 lines?
  2. When was the last release, and how many owners does it have?
  3. How many transitive crates does it add (cargo tree before and after)?
  4. Does it use unsafe, and is it widely used?
  5. What features can be turned off?

Disable default features you do not use: default-features = false often drops a quarter of the tree.

Automating

Run the scan on every pull request and on a daily schedule, since new advisories appear for old code. cargo deny combines advisories, license checks and bans, as in cargo deny configuration. Subscribe to security announcements of the crates you depend on most (the tokio, hyper and rustls projects publish advisories).

When there is no fix

Options: patch the dependency ([patch.crates-io] with a fork), replace it, or mitigate by restricting inputs. Record the decision and a review date in deny.toml as an ignored advisory with a reason, so the exception is visible.

Limits

Scanners only know reported problems. A new malicious release is not in the database yet, which is why lock files and review of updates matter. The database is documented at rustsec.org.

Taggedrustsec
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.