GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — Hosted cargo vex attests not_affected while Cargo.lock also builds an unpatched crates.io copy of the same crate@version · Issue #679 · SocketDev/socket-patch

Hosted cargo vex attests not_affected while Cargo.lock also builds an unpatched crates.io copy of the same crate@version #679

New issue
Copy link
New issue
Copy link
Closed
#1313
Closed
Hosted cargo vex attests not_affected while Cargo.lock also builds an unpatched crates.io copy of the same crate@version#679
#1313
Copy link
Labels
agent:triagedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentcompatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.pm:cargoCargoCargopriority:p1v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.

Description

@mikolalysenko
Mikola Lysenko (mikolalysenko)
opened on Oct 3, 2026
Issue body actions

[agent] Found by the scheduled Cargo bug-hunt routine (ledger #315).

Summary

After scan --mode hosted pins cfg-if 1.0.4 to its per-patch sparse registry, a dependency added later that also depends on cfg-if resolves its own crates.io cfg-if 1.0.4. Cargo can't unify packages from different sources, so Cargo.lock then holds two cfg-if 1.0.4 entries: the Socket one, used by the root crate, and the crates.io one, used by the new dependency. The build compiles both, so the new dependency links the unpatched bytes. socket-patch vex still emits pkg:cargo/[email protected] as not_affected ("Patched via Socket patch … (redirected)") with no warning.

scan already refuses this exact graph up front (redirect_cargo_transitive_dependents, "crc32fast compiled the unpatched crates.io copy while scan reported the crate redirected"). Post-scan vex has no equivalent guard, so the same graph is attested once it appears after the scan, for example after cargo add, cargo update or a merge.

Impact

This is a false VEX attestation: the shipped binary contains the vulnerable crate, and the VEX document says it doesn't. Adding a dependency after a hosted scan is the normal workflow. Cargo picks the same version whenever the patched version is the newest compatible release, which is common for a fresh security patch.

Repro (Linux, cargo 1.93.1 and 1.97.0)

I used a scratch copy of crates/socket-patch-cli/tests/e2e_redirect_cargo_shapes.rs (the wiremock sparse-registry harness), with the plain cfg-if = "1.0.4" consumer shape. After the harness's fresh checkout plus cargo fetch --locked and cargo build --locked --offline:

# fresh checkout of the hosted-scanned project
sed -i 's/^\[dependencies\]$/[dependencies]\ncrc32fast = "=1.5.0"/' Cargo.toml
cargo build                                              # crc32fast pulls crates.io cfg-if
cargo update -p [email protected] --precise 1.0.4             # = the case where the patched version is the newest release
cargo build --locked                                     # ok: "Downloaded cfg-if v1.0.4 … Compiling cfg-if v1.0.4" (crates.io)
socket-patch vex --output doc.vex.json --product pkg:cargo/[email protected] \
  --patch-server-url $MOCK --api-url $MOCK --org o --api-token fake --cwd .

Resulting Cargo.lock:

[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2…"

[[package]]
name = "cfg-if"
version = "1.0.4"
source = "sparse+http://127.0.0.1:34849/patch-registry/cargo/<token>/c1f90104-…/index/"
checksum = "cb5ea012…"

[[package]]
name = "crc32fast"
version = "1.5.0"
dependencies = [
 "cfg-if 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]

cargo tree -i [email protected] reports the spec as ambiguous, listing both sources. The vex output (exit 0):

"products": [{"@id": "pkg:cargo/[email protected]", "subcomponents": [{"@id": "pkg:cargo/[email protected]"}]}],
"status": "not_affected",
"impact_statement": "Patched via Socket patch c1f90104-… (redirected)"

Reproduced 3 times: twice on 1.93.1 and once on stable 1.97.0.

Expected vs actual

  • Expected (CLI_CONTRACT, "Manifest-less VEX", Contested locks): when the build resolves the same name@version from a non-Socket source beside the Socket wiring, the reference is dropped (patched_ref_unattributable) or the lockfile basis is withheld. The vlt row spells out the same-lock case: "A same-name@version node on another registry … keeps the reference but withholds the lockfile basis: only an installed tree whose every store copy verifies attests". The redirect refusal in scan documents that this graph builds an unpatched copy.
  • Actual: the cargo extractor accepts the Socket-sourced entry and ignores the crates.io sibling. Verification hashes only the Socket-registry source dir, so the purl is attested not_affected.

Matrix

OS cargo lock Reproduces
Linux 1.93.1 v4 yes (×2)
Linux 1.97.0 (stable) v4 yes
macOS / Windows any – untested (the logic is OS-independent)

First bad release: not bisected. Main is 045d7ec.

Suspect code

  • crates/socket-patch-core/src/vex/discover/cargo.rs:435 (hosted_from_lock): there's no check for another [[package]] with the same name+version and a non-Socket source. Compare cargo_unpinnable_dependents at crates/socket-patch-core/src/patch/redirect/mod.rs:1694, which scan uses to refuse the same graph.
  • npm analogue: npm vendored vex and vendor --check pass while a second registry copy of the patched package@version in the same package-lock.json stays unwired and installs unpatched #588 (vendored), npm VEX attests not_affected while a bundled (inBundle) copy of the same package@version stays unpatched #325 (bundled).

Activity

  1. Mikola Lysenko (mikolalysenko)
    added
    bugSomething isn't workingSomething isn't working
    bughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agent
    pm:cargoCargoCargo
    agent:triaged
    priority:p2
    on Oct 3, 2026
  2. mikolalysenko commented on Oct 3, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 3, 2026
    CollaboratorAuthor
    More actions

    [agent] Triaged: priority:p2 (Cargo). Shares the "same-lock unwired sibling contests the Socket ref" class with npm #588 (PR #589), but the fix lives in a different extractor (vex/discover/cargo.rs::hosted_from_lock), so it is tracked separately. No open or merged PR addresses it yet.


    Generated by Claude Code

  3. mikolalysenko commented on Oct 5, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 5, 2026
    CollaboratorAuthor
    More actions

    [agent] Follow-up from the Cargo bug-hunt routine (ledger #315), on main 99f61d2. No cargo vex code changed since the report, and I didn't re-run vex this time. What's new on the same contested lock:

    • Re-running scan --mode hosted exits 0 with redirected: 0 and a redirect_cargo_transitive_dependents warning saying cfg-if "was NOT redirected". But the existing Socket pin stays live in Cargo.toml / Cargo.lock, and the root crate keeps building it. So the only signal is a warning that describes the state wrongly. It never says that the crates.io sibling now builds unpatched beside the pin.
    • list --patch-server-url … shows pkg:cargo/[email protected] as discovered, with no contested-lock warning.
    • repair has nothing to do (manifest_not_found, since hosted keeps no manifest).
    • remove pkg:cargo/[email protected] on this lock exits 0 but writes a duplicate crates.io cfg-if 1.0.4 block, which cargo refuses to parse. Filed separately as Hosted cargo remove writes a duplicate cfg-if block into Cargo.lock when crates.io also locks the same crate@version, so cargo can no longer parse the lock while remove reports success #863.
    • A path sibling (an in-tree sib crate depending on cfg-if = "=1.0.4") produces the same contested lock as a registry dependent. The contested lock also forms on cargo 1.74.1 (lock v3) and on 1.97.0 (v3 and v4).

    Generated by Claude Code

  4. Mikola Lysenko (mikolalysenko)
    added
    priority:p1
    v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.
    compatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.
    and removed
    priority:p2
    on Oct 9, 2026
  5. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 9, 2026
    CollaboratorAuthor
    More actions

    v5 release blocker (P1). Ordinary Cargo graph changes can leave both hosted and registry copies. VEX must not claim the whole package version is patched when the build consumes an unpatched copy.

    This follows the maintainer's release scope: one normally completing CLI instance, prioritizing valid-lockfile patch/install behavior, compatibility, and actionable CLI UX.

  6. mikolalysenko commented on Oct 9, 2026

    @mikolalysenko
    Mikola Lysenko (mikolalysenko)
    on Oct 9, 2026
    CollaboratorAuthor
    More actions

    [agent] Claiming for v5 blocker burn-down (shared root cause: hosted cargo lock holding both a Socket and a crates.io copy of the same name@version (vex attests, restore duplicates block)). Branch: agent/v5-cargo-contested-lock. Claim-ID: 2026-10-09T16:41:36Z-317298

  7. Mikola Lysenko (mikolalysenko)
    added
    agent:claimed
    on Oct 9, 2026
  8. Mikola Lysenko (mikolalysenko)
    added a commit that references this issue on Oct 9, 2026

    Fix cargo locks that also hold a crates.io twin

    b532b71
  9. Mikola Lysenko (mikolalysenko)
    closed this as completedin #1313on Oct 9, 2026
  10. Mikola Lysenko (mikolalysenko)
    removed
    agent:claimed
    on Oct 11, 2026
  11. Mikola Lysenko (mikolalysenko)
    added a commit that references this issue on Nov 6, 2026

    Classify each Cargo declaration before judging a hosted pin

    7837fb4
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:triagedbugSomething isn't workingSomething isn't workingbughuntFound by a scheduled package-manager bug-hunt agentFound by a scheduled package-manager bug-hunt agentcompatibilityPublic CLI/JSON, saved state, upgrades, or package-manager compatibility.Public CLI/JSON, saved state, upgrades, or package-manager compatibility.pm:cargoCargoCargopriority:p1v5-blockerMust resolve before v5: public interface/migration or ordinary patch-install-undo failure.Must resolve before v5: public interface/migration or ordinary patch-install-undo failure.

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      You are visitor 01402503 — GeezerVison does not store the pages you look up.
      Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.