Dependency Confusion

Dependency confusion is a supply-chain attack in which a build resolves a malicious public package when the project intended to use a private package with the same name. It exploits ambiguity in dependency names and repository resolution rules.

A Java application may depend on packages hosted in a private artifact repository while also consuming public packages from repositories such as Maven Central. If an attacker publishes a public artifact using the same coordinates or package name as an internal dependency, a poorly controlled build configuration can select the attacker-controlled artifact.

The risk comes from the dependency resolver's view of repositories and versions, not from Java source code itself. Resolution behavior depends on the build tool, repository configuration, dependency coordinates, version constraints, and repository-management policies.

A strong defense is to make internal dependencies unambiguous and ensure builds resolve them only from trusted repositories. Organizations commonly use private repository managers, repository groups, namespace controls, dependency allowlists, lock or verification mechanisms, and publication protections for internal naming conventions.

Detection should include reviewing dependency provenance, unexpected package metadata, unfamiliar transitive dependencies, suspicious maintainer or publication changes, and build configuration changes. Dependency pinning and integrity verification reduce substitution risk, but they should complement controlled repository configuration rather than replace it.

Key points

Interview questions

Why isn't simply pinning the dependency version sufficient?

Pinning reduces uncertainty about which version is requested, but it does not by itself guarantee that the artifact came from the intended repository. If the pinned coordinates resolve to an attacker-controlled artifact or an attacker can influence the repository used for those coordinates, the build can still be compromised. Integrity verification and trusted repository configuration address different parts of the problem. The exact protection depends on the build and repository tooling in use.

What is dependency confusion, and how does it happen?

Dependency confusion occurs when an application expects an internal package but the build system retrieves a public package with the same dependency identity. An attacker first publishes the conflicting public package and may use a version that the resolver considers eligible. If repository configuration permits that public artifact to satisfy the internal dependency, malicious code can enter the build. The key issue is ambiguity in dependency resolution.

How would you prevent dependency confusion in a Java build?

I would make internal dependencies resolve through a controlled private repository and prevent ambiguous fallback to public repositories. Internal namespaces should have clear ownership and repository policies, and the organization should monitor attempts to register or publish conflicting names publicly. I would also use dependency locking or strict version constraints where appropriate and verify artifact integrity. CI should enforce the approved repository and dependency policy so individual developers cannot accidentally bypass it.

How would you investigate a suspected dependency-confusion incident?

I would first establish exactly which artifact and repository the affected builds resolved, including transitive dependencies and timestamps. I would compare the artifact against the organization's expected coordinates, checksums, metadata, and trusted repository records. I would then inspect CI logs, build configuration, dependency changes, and the suspicious artifact's behavior to determine exposure. Finally, I would isolate affected builds, rotate potentially exposed credentials or secrets when warranted, remove the untrusted dependency, and preserve evidence for incident analysis.

What is the difference between dependency confusion and a compromised legitimate dependency?

Dependency confusion substitutes an unintended package because the resolver is tricked by a naming or repository collision. A compromised legitimate dependency generally keeps the expected package identity while the trusted package itself, or its publication process, has been compromised. Both can introduce malicious code into a build, but the controls differ somewhat. Repository isolation and namespace controls are especially important for dependency confusion, while supplier security and artifact integrity are central for compromised legitimate dependencies.