Skip to content

Project-mode NuGet agent scan patches, and VEX attests, packages the project doesn't depend on (the crawler lists the whole ~/.nuget/packages) #427

Description

[agent] Found by the scheduled NuGet / dotnet bug-hunt routine (ledger #320).

Summary

Without -g, NuGet discovery for a .NET project lists every package in the user-wide global packages folder (~/.nuget/packages, %USERPROFILE%\.nuget\packages), not just the packages the project resolves. So, in a project that depends only on Newtonsoft.Json:

  • scan reports and looks up serilog@3.1.1, netstandard.library, … left over from unrelated projects on the same machine.
  • scan --mode agent --yes applies a patch to serilog@3.1.1 in the shared cache, which the project never uses, and records it in this project's .socket/manifest.json. Exit 0, 1 of 1 targeted patch applied.
  • vex --product pkg:nuget/App@1.0.0 then emits not_affected / inline_mitigations_already_exist with pkg:nuget/serilog@3.1.1 as a subcomponent of App. App doesn't contain serilog.

This is the NuGet twin of #265 (Maven: "the crawler lists all of ~/.m2").

Impact

  • A false VEX: the product's attestation names components it doesn't ship. That pollutes SBOM/VEX consumers and can mask the real dependency set.
  • Agent mode mutates bytes in a cache shared by every other project on the machine. The patch is recorded against this project, so another project's rollback / repair doesn't know about it.
  • Noise: scan output and the patch-API batch carry the whole machine cache (hundreds of packages on a dev box or warm CI image).

Repro (Linux, dotnet SDK 8.0.131, main 2463257)

SP=/path/to/target/release/socket-patch
export SOCKET_NO_CONFIG=1 SOCKET_TELEMETRY_DISABLED=1
# another project on this machine uses Serilog
mkdir other && cd other && cat > O.csproj <<'X'
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>net8.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Serilog" Version="3.1.1" /></ItemGroup></Project>
X
dotnet restore && cd ..
# our project depends only on Newtonsoft.Json
mkdir app && cd app && cat > App.csproj <<'X'
<Project Sdk="Microsoft.NET.Sdk"><PropertyGroup><TargetFramework>netstandard2.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Newtonsoft.Json" Version="13.0.3" /></ItemGroup></Project>
X
dotnet restore
grep -ci serilog obj/project.assets.json          # 0, not a dependency
# local stand-in for the public proxy (POST /patch/batch, GET /patch/by-package/<purl>,
# GET /patch/view/<uuid>) that serves one free patch for pkg:nuget/serilog@3.1.1 (README.md + marker line)
$SP scan --mode agent --yes --proxy-url http://127.0.0.1:8766
#   Found 4 packages (4 nuget) ... Patched packages: pkg:nuget/serilog@3.1.1 (via blob)
#   Summary: 1 of 1 targeted patch applied   (exit 0)
grep -c SOCKET_MARKER ~/.nuget/packages/serilog/3.1.1/README.md   # 1
$SP vex --offline --product pkg:nuget/App@1.0.0
#   products[0] = pkg:nuget/App@1.0.0, subcomponents = [pkg:nuget/serilog@3.1.1], status not_affected

Reproduced twice (rollback in between restores the bytes exactly). scan --json without --mode (report-only / hosted) also lists the unrelated packages.

Expected vs actual

  • Expected: project-mode discovery covers the packages this project resolves. For PackageReference projects that's the libraries in obj/project.assets.json (or packages.lock.json); for packages.config, the packages/ folder. The VEX contract (README VEX section, CLI_CONTRACT.md) attests only what is patched in the product. The maintainers' global-mode note (ledger Bug hunt ledger: NuGet / dotnet #320, 20261001T040000Z entry) also asks that a scan without -g never touch the global location beyond the project.
  • Actual: get_nuget_package_paths adds the whole global packages folder as a crawl root in local mode, and crawl_all emits every <id>/<ver>/ in it.

OS × SDK matrix

OS SDK unrelated cache package patched + attested
Linux (local) 8.0.131 yes (2/2 runs)

The crawler code path is OS-independent (the same nuget_home() root is used on macOS and Windows; the probe run https://github.com/SocketDev/socket-patch/actions/runs/36820498426 shows the same ~/.nuget/packages / C:\Users\runneradmin\.nuget\packages root being crawled on all 3 OSes). I haven't separately run this agent-mode scenario on macOS or Windows.

First bad version

Not a regression: v4.0.0 (scan --apply --yes) patches serilog@3.1.1 the same way.

Suspect code

crates/socket-patch-core/src/crawlers/nuget_crawler.rs:74-78 (// 2. Fall back to the global cache. pushes nuget_home() as a crawl root in local mode). A fix would crawl only the <id>/<ver> dirs named in obj/project.assets.json libraries (resolved against its packageFolders) instead of the whole folder. That would also fix the wrong-folder half of #397.

No activity

Activity on this issue will appear here.

Activity

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 workingbughuntFound by a scheduled package-manager bug-hunt agentpm:nugetNuGet / dotnetpriority:p3

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions