You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Hosted NuGet splices the Socket source (and mapping) into a commented-out <packageSources> / <packageSourceMapping> block, so every restore fails NU1100 while scan reports success and its in-run VEX attests not_affected #585
[agent] Found by the scheduled NuGet / dotnet bug-hunt routine (ledger #320).
Summary
The hosted NuGet rewriter finds its splice anchors with regexes that don't skip XML comments. In insert_nuget_source, the <packageSources> open-tag regex matches the first occurrence, and so does the <packageSourceMapping> regex in nuget_mapping_open_end. If a nuget.config has a commented-out <packageSources> block before the real one (common in templates and docs), the Socket <add> lands inside the comment. The new exclusive <packageSourceMapping> is outside the comment, so it routes Newtonsoft.Json to a source that NuGet never reads. Every restore then fails NU1100.
The scan still exits 0 with success and redirected: 1. Its in-run --vex attests not_affected. A re-run reports redirected: 1 again and changes nothing. A later standalone vex sees the problem (patched_ref_invalid: "routes packages to socket-patch-…, which no <packageSources> entry defines") and refuses. remove pkg:nuget/newtonsoft.json@13.0.3 fails with manifest_not_found, so the user can't undo the change with the CLI.
The vendored writer handles both shapes (it blanks comments first). Only hosted is affected.
This is separate from #561, which covers how hosted reads source keys from comments. #561's "Out of scope" note asks for the splice-anchor case to be filed separately if it can match inside a comment. It can. Variant A below has no <add> inside the comment, so #561's key reading isn't involved.
Impact
Variant A (a commented <packageSources> before the real one): the project can no longer restore at all (NU1100, locked or not). Meanwhile scan reports success and the in-run VEX claims the vulnerability is not exploitable.
I used the wiremock patch API and NuGet feed stand-in from crates/socket-patch-cli/tests/e2e_nuget_dotnet_build.rs (Backend::start), with a real nuget.org fixture restore of Newtonsoft.Json 13.0.3.
cat > nuget.config <<'EOF'<?xml version="1.0" encoding="utf-8"?><configuration> <!-- <packageSources></packageSources> --> <packageSources> <add key="nuget.org" value="https://api.nuget.org/v3/index.json" /> </packageSources></configuration>EOF# app.csproj: net8.0, RestorePackagesWithLockFile=true, PackageReference Newtonsoft.Json 13.0.3
dotnet restore
socket-patch scan --mode hosted --json --yes --api-url $URI --org test-org --api-token x \
--patch-server-url $URI --vex vex.json --vex-product pkg:nuget/app@1.0.0
# -> rc 0, status success, redirected 1; vex.json: not_affected
rm -rf obj; NUGET_PACKAGES=$(mktemp -d) dotnet restore --locked-mode
# -> error NU1100: Unable to resolve 'Newtonsoft.Json (>= 13.0.3)' for 'net8.0'.# PackageSourceMapping is enabled, the following source(s) were not considered: nuget.org.
Hosted output: the Socket <packageSource> is inserted inside the comment, and no live mapping is authored.
Expected vs actual
Expected: hosted mode wires the Socket source and an exclusive exact-id mapping that the next restore honours (README / docs/ecosystems.md NuGet row: "adds a Socket package source plus an exact-id packageSourceMapping, and re-pins contentHash"). If it can't, it refuses rather than reporting success. VEX attests only a patch that will actually be installed (CLI_CONTRACT.md: VEX statements are backed by a wired patch).
Actual: the source or mapping is written into a comment. Scan says success, the in-run VEX attests not_affected, and the restore fails NU1100 (variant A) or loses exclusivity (variant B).
Matrix
OS
SDK
mode
variant A (commented <packageSources>)
variant B (commented <packageSourceMapping>)
control (no comment)
Linux
8.0.131
hosted
fail (NU1100), 3×
fail (mapping inside comment; restore patched by luck)
pass
Linux
8.0.131
vendored
pass
pass
pass
macOS / Windows, SDK 6/9/10
hosted
untested (the defect is pure text splicing, OS- and SDK-independent; installing other SDKs is blocked in this sandbox)
v4.0.0 (npm) also reproduces variant A: the Socket <add> lands in the comment, the in-run VEX says not_affected, and the restore fails NU1100. This is not a regression.
Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:4289insert_nuget_source: the open_tag regex <packageSources(?:\s[^>]*)?> and the self_closing regex both use .find(config) on unmasked text.
crates/socket-patch-core/src/patch/redirect/mod.rs:4346nuget_mapping_open_end: the same issue for <packageSourceMapping>.
nuget_after_last_clear (just below) already blanks <!-- … --> in place. The same masking, applied before these finds, would fix it. Alternatively, move to formats::nuget as Hosted NuGet mapping reads commented-out package sources #561 proposes.
In-run VEX trusts the rewrite, while standalone vex (vex/discover/nuget.rs, which uses comment-aware formats::nuget::parse_config) flags patched_ref_invalid.
No probe run: the defect is OS-independent string splicing.
[agent] Found by the scheduled NuGet / dotnet bug-hunt routine (ledger #320).
Summary
The hosted NuGet rewriter finds its splice anchors with regexes that don't skip XML comments. In
insert_nuget_source, the<packageSources>open-tag regex matches the first occurrence, and so does the<packageSourceMapping>regex innuget_mapping_open_end. If anuget.confighas a commented-out<packageSources>block before the real one (common in templates and docs), the Socket<add>lands inside the comment. The new exclusive<packageSourceMapping>is outside the comment, so it routesNewtonsoft.Jsonto a source that NuGet never reads. Every restore then fails NU1100.The scan still exits 0 with
successandredirected: 1. Its in-run--vexattestsnot_affected. A re-run reportsredirected: 1again and changes nothing. A later standalonevexsees the problem (patched_ref_invalid: "routes packages to socket-patch-…, which no<packageSources>entry defines") and refuses.remove pkg:nuget/newtonsoft.json@13.0.3fails withmanifest_not_found, so the user can't undo the change with the CLI.The vendored writer handles both shapes (it blanks comments first). Only hosted is affected.
This is separate from #561, which covers how hosted reads source keys from comments. #561's "Out of scope" note asks for the splice-anchor case to be filed separately if it can match inside a comment. It can. Variant A below has no
<add>inside the comment, so #561's key reading isn't involved.Impact
<packageSources>before the real one): the project can no longer restore at all (NU1100, locked or not). Meanwhile scan reports success and the in-run VEX claims the vulnerability is not exploitable.<packageSourceMapping>, with no real mapping): the whole Socket mapping (the exact-id route plus the*fan-out) is spliced into the comment. No mapping is active, so exclusivity is lost. With a cold cache and a lock, restore happened to pick the Socket feed (it's listed first) and installed the patched bytes. Without a lock, NuGet picks whichever source answers. This is the same class of risk as Hosted/vendored NuGet mapping isn't exclusive when nuget.config already maps the exact package id to another source, so restore races the Socket feed against nuget.org (NU1403 with a lock, silently unpatched without one) #462.Repro (Linux, SDK 8.0.131, main
6cd3754)I used the wiremock patch API and NuGet feed stand-in from
crates/socket-patch-cli/tests/e2e_nuget_dotnet_build.rs(Backend::start), with a real nuget.org fixture restore of Newtonsoft.Json 13.0.3.Resulting
nuget.config(variant A):(The seeded
nuget.org<add>also lands in the comment. #561's key reader sees no keys in the empty commented region, so it seeds one.)Variant B input: the real
<packageSources>with nuget.org, followed byHosted output: the Socket
<packageSource>is inserted inside the comment, and no live mapping is authored.Expected vs actual
packageSourceMapping, and re-pinscontentHash"). If it can't, it refuses rather than reporting success. VEX attests only a patch that will actually be installed (CLI_CONTRACT.md: VEX statements are backed by a wired patch).Matrix
<packageSources>)<packageSourceMapping>)v4.0.0 (npm) also reproduces variant A: the Socket
<add>lands in the comment, the in-run VEX says not_affected, and the restore fails NU1100. This is not a regression.Suspect code
crates/socket-patch-core/src/patch/redirect/mod.rs:4289insert_nuget_source: theopen_tagregex<packageSources(?:\s[^>]*)?>and theself_closingregex both use.find(config)on unmasked text.crates/socket-patch-core/src/patch/redirect/mod.rs:4346nuget_mapping_open_end: the same issue for<packageSourceMapping>.nuget_after_last_clear(just below) already blanks<!-- … -->in place. The same masking, applied before these finds, would fix it. Alternatively, move toformats::nugetas Hosted NuGet mapping reads commented-out package sources #561 proposes.vex(vex/discover/nuget.rs, which uses comment-awareformats::nuget::parse_config) flagspatched_ref_invalid.No probe run: the defect is OS-independent string splicing.