Skip to content

Harden Maven registry trust for pom.xml sourced entries#1970

Open
TristanInSec wants to merge 1 commit intogoogle:mainfrom
TristanInSec:harden-maven-registry-trust
Open

Harden Maven registry trust for pom.xml sourced entries#1970
TristanInSec wants to merge 1 commit intogoogle:mainfrom
TristanInSec:harden-maven-registry-trust

Conversation

@TristanInSec
Copy link
Copy Markdown

Summary

Follows up on #1877 and ports the hardening that was originally staged against osv-scanner (PR google/osv-scanner#2713, closed in favour of landing the fix here). Registries discovered while scanning a user supplied pom.xml are treated as untrusted input throughout clients/datasource.

  • MavenRegistryAPIClient.AddRegistry now validates the URL before recording it. The scheme must be http or https, and the host must resolve exclusively to public unicast addresses. Loopback, private, link local, unspecified and multicast destinations are rejected so a scanned pom.xml cannot steer requests at the local host, cloud metadata endpoints, or internal infrastructure. The default registry passed to NewMavenRegistryAPIClient is exempt, so users can still point the client at an internal Artifactory or Nexus mirror.
  • MavenRegistry now carries a TrustedForAuth flag. It is only set on the default registry constructed through NewMavenRegistryAPIClient; AddRegistry always clears it, even for callers that try to set it explicitly. The three fetch helpers (getProject, getVersionMetadata, getArtifactMetadata) now go through a small authFor helper that refuses to attach settings.xml credentials to untrusted registries. That prevents a scanned pom.xml from reusing a known settings.xml <server> ID to exfiltrate the associated credentials to an attacker-chosen URL.

Test plan

  • go test ./clients/datasource/...
  • go test ./clients/... ./internal/mavenutil/... ./enricher/transitivedependency/pomxml/... ./guidedremediation/internal/manifest/maven/...
  • go vet ./clients/datasource/...
  • New table-driven tests cover non-http schemes, loopback / RFC1918 / link-local literals, DNS-rebind style public-to-private resolutions, a pom.xml attempt to overwrite the default registry ID, and TrustedForAuth smuggling via a caller supplied struct. Existing TestMultipleRegistry, TestUpdateDefaultRegistry and TestWithoutRegistriesMaintainsAuthData stub lookupHost so their mock HTTP servers remain reachable under the new validator.

Registries discovered while scanning third party pom.xml files are
passed into MavenRegistryAPIClient.AddRegistry as untrusted input,
since any repository URL declared inside a scanned project is under
the control of whoever authored that project. Two tightenings:

- AddRegistry now validates the URL: it must use http or https and
  resolve exclusively to public unicast addresses. Loopback, private,
  link local, unspecified and multicast destinations are rejected so
  a scanned pom.xml cannot steer requests at the local host, cloud
  metadata services or internal infrastructure. The default registry
  configured through NewMavenRegistryAPIClient is exempt, so users
  can still point the client at an internal Artifactory or Nexus.

- MavenRegistry now carries a TrustedForAuth flag. It is only set by
  the default registry path, and AddRegistry forces it off for any
  registry it accepts. Requests against untrusted registries go out
  with a nil HTTPAuthentication, so a scanned pom.xml can no longer
  reuse a known settings.xml server ID to exfiltrate the associated
  credentials to an attacker chosen URL.

The three fetch helpers (getProject, getVersionMetadata,
getArtifactMetadata) now route through a small authFor helper that
centralises this policy. Unit tests cover scheme rejection, public
address enforcement, DNS rebind style cases, default registry
overwrite attempts, and the credential gating behaviour.

Issue: google#1877
@G-Rath
Copy link
Copy Markdown
Collaborator

G-Rath commented Apr 10, 2026

It would be good if you could contrast the differences in your PR with #1931, as I believe that is attempting to address the same issue in a similar but not identical way

@TristanInSec
Copy link
Copy Markdown
Author

TristanInSec commented Apr 10, 2026

Quick contrast:

#1931 narrowly targets the credential exfiltration angle. It rejects non-https (and non-artifactregistry) URLs in AddRegistry / updateDefaultRegistry, but only when registryAuths is already populated for that registry ID.

#1970 treats every registry coming out of a scanned pom.xml as untrusted input regardless of whether credentials happen to be configured for its ID, and splits the hardening into two layers:

  1. URL validation on AddRegistry entry. Scheme and host policy applied unconditionally, not gated on whether an auth entry already exists for that ID.
  2. A TrustedForAuth flag on MavenRegistry that is only set by the default registry path. AddRegistry always clears it, and the three fetch helpers route through a new authFor helper that returns nil for untrusted registries. Credential attachment becomes independent of the caller's scheme, ID choice, or struct contents.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants