Skip to content

VNX-RUST-001: Missing Cargo.lock

Reports a Cargo.toml that declares dependencies but has no Cargo.lock in its own or any ancestor directory; workspace members covered by the root lock, manifests with empty dependency tables, and test/fixture/example manifests are not reported.

Updated 02 Nov 2026Checked against cli@de9b52a
Field Value
Rule ID VNX-RUST-001
Severity High
SARIF level error
Kind sast
Languages Rust
CWE CWE-829
CAPEC CAPEC-185
ATT&CK T1195.001
CWSS vector CWSS:1.0/TI:H/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:H/DI:H/EX:H/EC:N/P:H
Tags supply-chain lockfile integrity
Source internal/sast/rules/vnx-rust-001.rego

Overview

This rule detects Rust project directories where Cargo.toml is present but Cargo.lock is absent. Without a lock file, cargo build resolves dependency version ranges non-deterministically at build time: the exact versions selected depend on what is available in the crates.io index at that moment. This means two builds of the same source tree can silently incorporate different dependency versions, including versions that introduce security vulnerabilities or malicious code. This maps to CWE-829 (Inclusion of Functionality from Untrusted Control Sphere).

Why This Matters

Supply chain attacks against package registries have become one of the most effective attack vectors in software security. The cargo ecosystem has seen incidents including the rustdecimal typosquatting attack and the broader pattern of maintainer account takeovers used to push malicious patch releases. When a crate you depend on is compromised (e.g., serde@1.0.193 becomes malicious), a build without a lock file will pull the compromised version if it satisfies your version constraint in Cargo.toml.

With a Cargo.lock file committed to version control, the exact version hash of every transitive dependency is pinned. A cargo audit or cargo deny check against the lock file can detect known-vulnerable versions before the build proceeds. Without the lock file, you have no stable dependency inventory to audit.

The Cargo team’s official guidance is that all binary crates (applications) should commit Cargo.lock, and MITRE ATT&CK T1195.001 (Compromise Software Dependencies and Development Tools) covers this attack class directly.

What Gets Flagged

The finding is reported on line 1 of the Cargo.toml of a crate that declares at least one dependency ([dependencies], [dev-dependencies], [build-dependencies], [workspace.dependencies], [target.*.dependencies] or a [dependencies.<name>] table) when no Cargo.lock exists in that directory or any ancestor:

services/worker/
├── Cargo.toml       ← FLAGGED: [dependencies] tokio = "1"
├── src/main.rs
└── (no Cargo.lock here or in services/ or the repository root)

Not flagged: a workspace member such as crates/core/Cargo.toml when the workspace root has a Cargo.lock, a manifest whose dependency tables are empty, and manifests under tests/, fixtures/, examples/ or mock directories.

Remediation

  1. Generate Cargo.lock immediately and commit it to version control.

    # Generate the lock file
    cargo generate-lockfile
    
    # Verify it was created
    ls -la Cargo.lock
    
    # Add it to git
    git add Cargo.lock
    git commit -m "chore: add Cargo.lock to pin dependency versions"
  2. Update your .gitignore to stop ignoring Cargo.lock for binary crates. A common mistake is adding Cargo.lock to .gitignore based on library crate advice without recognizing that binary crates should always commit it.

    # WRONG for binary crates, remove this line:
    # Cargo.lock
    
    # If you have a mixed workspace (libraries + binaries),
    # use per-package overrides or commit the lock file
  3. Add cargo audit to your CI pipeline. Once the lock file is committed, cargo audit checks it against the RustSec Advisory Database (a curated database of Rust security advisories) and fails the build if any dependency has a known vulnerability.

    # GitHub Actions example
    - name: Security audit
      run: |
        cargo install cargo-audit --locked
        cargo audit
  4. Use cargo deny for comprehensive supply chain policy. cargo-deny extends cargo audit with license checks, banned crate lists, and alternative registry enforcement. This provides a complete supply chain policy as code.

    # deny.toml
    [advisories]
    db-path = "~/.cargo/advisory-db"
    db-urls = ["https://github.com/rustsec/advisory-db"]
    vulnerability = "deny"
    unmaintained = "warn"
  5. Pin to exact versions in Cargo.toml for security-critical dependencies. Using =1.2.3 instead of ^1.2.3 eliminates the version range entirely, though this makes updating more manual. A lock file provides the same protection with more flexibility.

References

Suppressing this rule

Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):

# nosec vnx-rust-001
// nosec vnx-rust-001

Or record an ignore rule: vulnetix ignore add --rule vnx-rust-001 --reason "...". See Suppressing findings.

Edit this pageSources: cli/internal/sast/rules/vnx-rust-001.rego, cli/internal/sast/docs/vnx-rust-001.md
esc
↑ ↓ move↵ openSearches in your browser. A key like autonomy.max or a code like threshold_required jumps straight to it.