Run cargo package --list before every release. It prints the files that would go into your .crate archive without creating it. Compare the list with what you expect, tighten the include or exclude fields in Cargo.toml, and only then run cargo publish.
Why this matters
A published version is permanent. The Cargo publishing documentation says a version can never be overwritten and its code cannot be deleted. Yanking marks it as broken for new dependencies, but does not remove the code, and the docs say not to use it to hide a secret that was uploaded by accident. If a token or key ships, you must reset it.
So the cheap moment to catch a mistake is before publishing.
What cargo package does
According to the reference, it builds a compressed .crate file in target/package. Along the way it:
- Rewrites and normalises
Cargo.toml, and removes patch, replace and workspace sections. - Always includes
Cargo.lock, generating one if missing, unless told otherwise. - Adds a small
.cargo_vcs_info.jsonrecording the commit and whether the worktree was dirty. - Replaces symlinks with the files they point to.
- Rebuilds the extracted package from scratch to check it compiles on its own.
- Confirms build scripts did not modify source files.
The VCS info file is a best effort snapshot. Cargo does not verify that the archive matches the recorded commit.
Steps
- Commit your work so the dirty flag reads false.
- List the files:
cargo package --list
- Read every line. Look for environment files, key material, test fixtures with real data, editor files, large binaries and internal notes.
- Add an allow list or a deny list:
[package]
include = ["src/**/*", "Cargo.toml", "README.md", "LICENSE"]
# or, instead of include
# exclude = ["tests/fixtures/*", "*.psd"]
- Run the list again and confirm.
- Build the archive and test it, then publish with a token you can revoke.
Include or exclude
An include list is safer, because a new file does not ship unless you add it. An exclude list is easier to maintain but can leak a new sensitive file by default. For crates with a small source tree, prefer include.
Add it to CI
Run the list and the packaging step on release branches. Add a simple check that fails if the output contains patterns you never want, such as environment file names. Keep that check short and visible.
What it does not catch
It will not tell you that a string inside a source file is a secret. Pair it with secret scanning on the repository.
Quick check
Does cargo package upload anything?
No. It builds the archive locally. Publishing is a separate step.
I published a secret. Does yanking fix it?
No. Yanking does not delete code. Reset the secret immediately.
Safeguard asset discovery and SBOM and dependency scanning can help you see what you ship, and a free scan is available at gold.safeguard.sh/scan.
Sources
Last reviewed: 19 October 2026.