Skip to content

Maven hosted scan pins, and VEX attests, artifacts the project doesn't depend on (the crawler lists all of ~/.m2) #265

Description

[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)

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

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions