Maven is most frequently done with a pinned version and rules about the order and depth of dependencies.
libBar:1.0
libFoo:1.1
libFoo:1.0
In this example, libFoo:1.0 is defined at a higher level than the transitive dependency for libBar which defined libFoo:1.1 -- libFoo:1.0 will be the version used.
libBar:1.0
libFoo:1.1
libQux:1.0
libFoo:1.2
Here, libBar is defined earlier in the dependencies. libFoo is used by both libBar and libQux, but since libBar was defined earlier, it has precedence.
There are ways for the project to specifically redefine versions to be used, exclude certain dependencies, prevent the build if certain versions show up and enforce various rules upon the build.
This is even worse, it doesn't satisfy the constraints at all! If libBar needs features added to libFoo 1.1, it will crash with NoSuchMethodError, even though they declared their dependency correctly. That's madness.
* Manage the dependency to libFoo:1.1
* Put libFoo:1.1 as a top level dependency for the project
* Exclude libFoo:1.0 as a dependency from projects that include it
There are many ways to go about this.
The key thing with this is that the dependencies are deterministic, reasonable, and repeatable.
They are as deterministic and repeatable as any lock file from any tool that has lock files (npm, poetry, pipenv, cargo, ...). They just don't offer a way to generate that manifest (which is a lock file) correctly automatically, instead you have to do that dependency resolution yourself.
Is that reasonable? I certainly don't think so. This sheds light on why log4j is such a large-scale issue.
While that speaks of code - the key in there is the ability to look at it and figure out how it works and how to change it.
With Log4j, we had to select one of those approaches, rebuild, and redeploy. In the Java community, repeatable builds are valued - the "I build the jar today" should have the same result tomorrow as the default.
It is possible to change the way maven specifies its versions to do ranges, just most people don't do that. I don't want my oracle ojdbc jar to suddenly jump to a different version that doesn't work with the backend I'm running.
If you look at the "downloads per hour" you'll see that about half the people using it downloaded it and continued to update their code as new releases came out.
It is concerning that 41% of the builds out there are still specifying a vulnerable version.