[agent] Filed by Claude Code on behalf of Mikola Lysenko (@mikolalysenko) while adding Maven patch SBOM annotations to depscan. Repro artifacts were produced with real Maven and a stub patch API.
Summary
The Maven crawler discovers packages by walking the whole local repository (scan_maven_repo). It never uses the project's dependency graph. In hosted fail-closed mode, a GA that is absent from pom.xml is treated as "transitive" and gets a <dependencyManagement> pin. That pin comes with the Socket <repository> and the .mvn Trusted Checksums files.
So on any machine with a shared ~/.m2, running scan --mode hosted in project A pins every patchable artifact that some other project B cached. socket-patch vex then emits not_affected statements for those components under project A's product.
Impact
- Poms get polluted with pins for unrelated artifacts, plus a repository prepended ahead of Central. Every cold build then asks
patch.socket.dev for every artifact first.
- A depMgmt pin is not inert. If the project later picks up the GA transitively at a newer version, Maven's dependency management forces it down to the pinned
<old base>-socket.<hex8>.
- The VEX document lists components that are not in the product.
- Results depend on whatever happens to be in the developer's cache, so they are not reproducible between CI (cold cache: nothing found) and laptops (warm cache: everything found).
Repro
The project pom depends only on junit:junit:4.13.2 (test scope). MAVEN_REPO_LOCAL holds junit/junit/4.13.2 and also org/apache/commons/commons-lang3/3.12.0, as if cached by another project. The stub grants commons-lang3 3.12.0 → 3.12.0-socket.4d5e6f70.
socket-patch scan --mode hosted --json --yes ...
-> exit 0, redirected=1, rewrittenFiles=[.mvn/checksums/checksums.sha256, .mvn/maven.config, pom.xml],
warnings=[redirect_maven_dep_management_added]
pom.xml gains <dependencyManagement> commons-lang3 3.12.0-socket.4d5e6f70 + <repositories> socket-patch-4d5e6f70-…
socket-patch vex --no-verify --product pkg:maven/com.example/unrelated-app@1.0.0
-> not_affected GHSA-… for pkg:maven/org.apache.commons/commons-lang3@3.12.0
Expected vs actual
- Expected: hosted/vendored Maven targets only artifacts in the project's resolved graph. Otherwise it refuses to add a depMgmt pin for a GA the pom never mentions, unless the user opts in, for example with
--include-transitive or an explicit purl list.
- Actual: anything in
~/.m2 is pinned and attested.
CLI revision
3efdc31d
Suggested fix
Short term:
- Only add the transitive depMgmt pin when the GA is demonstrably in the project's graph. One option is to run
mvn dependency:list when Maven is available. Another is to intersect with the artifacts referenced from the project's poms and their already-cached transitive poms.
- Otherwise warn
redirect_maven_dep_not_found, as legacy mode already does, and skip.
Longer term: scope discovery to the project, like the other ecosystems' lockfile-driven crawls.
File refs (at 3efdc31)
crates/socket-patch-core/src/crawlers/maven_crawler.rs:348 (get_maven_repo_paths: the local repo for any cwd with a pom.xml)
crates/socket-patch-core/src/crawlers/maven_crawler.rs:502 (scan_maven_repo: walkdir of the whole repo)
crates/socket-patch-core/src/patch/redirect/mod.rs:6143-6170 (a GA with no match gets a depMgmt pin)
[agent] Filed by Claude Code on behalf of Mikola Lysenko (@mikolalysenko) while adding Maven patch SBOM annotations to depscan. Repro artifacts were produced with real Maven and a stub patch API.
Summary
The Maven crawler discovers packages by walking the whole local repository (
scan_maven_repo). It never uses the project's dependency graph. In hosted fail-closed mode, a GA that is absent frompom.xmlis treated as "transitive" and gets a<dependencyManagement>pin. That pin comes with the Socket<repository>and the.mvnTrusted Checksums files.So on any machine with a shared
~/.m2, runningscan --mode hostedin project A pins every patchable artifact that some other project B cached.socket-patch vexthen emitsnot_affectedstatements for those components under project A's product.Impact
patch.socket.devfor every artifact first.<old base>-socket.<hex8>.Repro
The project pom depends only on
junit:junit:4.13.2(test scope).MAVEN_REPO_LOCALholdsjunit/junit/4.13.2and alsoorg/apache/commons/commons-lang3/3.12.0, as if cached by another project. The stub grants commons-lang3 3.12.0 →3.12.0-socket.4d5e6f70.Expected vs actual
--include-transitiveor an explicit purl list.~/.m2is pinned and attested.CLI revision
3efdc31dSuggested fix
Short term:
mvn dependency:listwhen Maven is available. Another is to intersect with the artifacts referenced from the project's poms and their already-cached transitive poms.redirect_maven_dep_not_found, as legacy mode already does, and skip.Longer term: scope discovery to the project, like the other ecosystems' lockfile-driven crawls.
File refs (at 3efdc31)
crates/socket-patch-core/src/crawlers/maven_crawler.rs:348(get_maven_repo_paths: the local repo for any cwd with apom.xml)crates/socket-patch-core/src/crawlers/maven_crawler.rs:502(scan_maven_repo: walkdir of the whole repo)crates/socket-patch-core/src/patch/redirect/mod.rs:6143-6170(a GA with no match gets a depMgmt pin)