Open Source Security

Rust Cargo Supply Chain Defence Program

A 2026 defence program for Rust and Cargo — covering crates.io, build scripts, proc-macros, and binary provenance — anchored by Safeguard policy gates.

Shadab Khan
Security Engineer
7 min read

Rust is on the cusp of a category transition that every other major language ecosystem has already lived through. The crates.io registry has crossed the volume threshold where the manual review and small-community trust model that worked at a hundred thousand crates is creaking at half a million. The tooling ecosystem — build scripts, proc-macros, and the dozens of utility crates everyone depends on — is now large enough that no team can plausibly read it. And Rust has become attractive enough as a platform that the people who used to attack npm and PyPI are starting to look at it.

The 2026 Rust program is the one that takes those facts seriously without sacrificing what makes Rust appealing in the first place: a strong language-level safety story, a mature build tool, and a community that still expects high signal-to-noise in its libraries.

What is different about Rust

Three properties of the Rust ecosystem shape the program more than any others.

The first is build.rs. Cargo runs a build script for any crate that ships one, with full filesystem and network access, on every clean build. Build scripts are how Rust links to C libraries, generates code, and probes the host environment, and they execute on every developer machine and CI runner that compiles the crate. A malicious build.rs is indistinguishable from any other compromised dependency, except that it runs at compile time on every consumer.

The second is procedural macros. Proc-macros are crates that run arbitrary Rust code at compile time to expand into more Rust code. They have access to the source they expand and the build environment they run in, and they are pervasive in modern Rust codebases. A compromised proc-macro can rewrite source on the way through the compiler in ways that no source review will catch.

The third is the binary output. Like Go, Rust statically links by default, which means the binary contains every transitive dependency. Unlike Go, Rust binaries frequently link against C libraries through build scripts, which means the supply chain extends beyond the Cargo.toml graph into whatever the build script pulled in.

A 2026 program has to address all three.

Layer one: the registry

Crates.io is a well-run registry, but it is still upstream of your trust boundary. The 2026 baseline is a private mirror — a Cargo registry server like Kellnr, Cloudsmith, or a private Artifactory feed — configured as the source of record for every developer and CI runner. The mirror proxies crates.io with a quarantine in front of it.

Safeguard ingests the mirror events and runs policy on every new crate version. The policy includes blocklists for known-malicious crates, typosquat heuristics against the existing namespace, license rules, age thresholds, and a maintainer-trust score. Yanked crates upstream are propagated downstream automatically, and the cool-down period before promotion is non-negotiable.

The cool-down matters more in Rust than in some other ecosystems because crates.io's takedown response is fast and effective. The vast majority of malicious crates are removed within hours of publication. A short quarantine catches most of them before they ever reach a developer.

Layer two: the dependency graph

Cargo.lock is the single source of truth for what the build will use. The 2026 program treats the lockfile as committed-to-the-repo policy: every CI build uses --locked, every install verifies hashes, and any pull request that changes Cargo.toml or Cargo.lock is gated by a policy evaluation.

The gates cover the standard ground: blocklists, license rules, CVE floors, age thresholds, maintainer minimums. Rust adds two ecosystem-specific gates that are worth running on every change.

The first is a feature-flag review. Cargo features can change the dependency graph in non-obvious ways, including pulling in optional dependencies that have their own transitive trees. Safeguard surfaces the feature delta on every change so that the reviewer can see what is actually being added.

The second is a no_std vs std review for crates that target embedded or kernel environments. Pulling in a std-only transitive dependency into a no_std crate is usually a mistake and is occasionally a security incident — most often when an embedded build silently grows a dependency on a heavy networking crate that nobody intended.

Layer three: build scripts and proc-macros

This is where the Rust program differs most from other ecosystems. Build scripts and proc-macros are both arbitrary code execution at compile time, and the 2026 program treats them as the highest-risk surface in the dependency graph.

The control is a tiered review. Crates without a build.rs and without proc-macro exports get the standard policy treatment. Crates with a build.rs get an additional review that surfaces what the script does — does it run pkg-config, does it download anything, does it write outside the OUT_DIR. Crates that export proc-macros get the most scrutiny, with an explicit allowlist that requires a human review for new additions and version bumps that change the macro surface.

Safeguard maintains the allowlist as policy and surfaces every change in the dependency graph that touches it. The aim is not to forbid build scripts and proc-macros, which would be impossible in modern Rust, but to make the surface visible and reviewable rather than invisible and trusted.

Layer four: the build

Rust builds are slow but simple. Cargo handles dependency resolution, build script execution, proc-macro expansion, and final linking in one tool. The 2026 build environment is the same as for every other language: ephemeral runners, restricted egress (the private registry plus whatever the project explicitly requires), single-use credentials, and a signed output.

The output is a binary, a CycloneDX SBOM, and a SLSA provenance statement. The SBOM is generated from the resolved Cargo.lock plus any C libraries that build scripts pulled in via system pkg-config. Safeguard reconciles the two and stores them together as the canonical inventory for the binary.

For projects that target multiple platforms — most non-trivial Rust projects do — the SBOM is generated per target. A linux-x86_64 build and a windows-x86_64 build of the same project can have different transitive dependencies because of platform-specific cfg attributes, and the program tracks them as distinct artefacts.

Layer five: runtime

Like Go, Rust does not have a runtime in the JVM sense. The runtime is the binary, plus whatever it dynamically opens — a TLS implementation, a database client, sometimes a Python or Node embedded interpreter. Safeguard's inventory layer links each running binary back to its SBOM and provenance, and treats a CVE against any embedded crate as a CVE against the binary.

When a new RustSec advisory drops — and the RustSec advisory database is one of the better-curated security feeds in any ecosystem — the question "where are we affected?" is a query against the inventory.

The cultural layer

Every Rust supply chain conversation eventually arrives at cargo-vet and cargo-crev, the community efforts to build a distributed audit layer for crates. The 2026 program treats both as inputs to the policy rather than replacements for it. A crate with positive cargo-vet attestations from organisations you trust is a stronger candidate for promotion than one without, but the attestation is one signal among many, not the verdict.

Safeguard ingests cargo-vet metadata as an additional policy input, alongside RustSec advisories, license data, and the in-house allowlist for build scripts and proc-macros. The output is a single verdict on every dependency change.

The result

A 2026 Rust supply chain program looks like the programs for every other modern language ecosystem, with three Rust-specific additions: a build-script and proc-macro allowlist, a feature-flag and platform-specific SBOM model, and a deliberate stance on the community attestation tooling. The shape is familiar; the details matter. Safeguard is the layer that holds the details together.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.