fix: #8140 AssemblyAnalyzer version resolution issue#8352
Merged
Conversation
Consider the parsed version bringing the most fine-grained information if the smaller one fully corresponds to the longer one and consider ProductVersion has a higher confidence value
nhumblot
commented
Mar 6, 2026
| && data.getFileVersion().length() >= data.getProductVersion().length()) { | ||
| if (fileVersion != null && fileVersion.toString().length() == data.getFileVersion().length()) { | ||
| if (fileVersion != null && productVersion != null) { | ||
| if (fileVersion.toString().startsWith(productVersion.toString())) { |
Collaborator
Author
There was a problem hiding this comment.
note: See the mention of Priority 2 in the behavior change of the PR description for additional information.
nhumblot
commented
Mar 6, 2026
| } | ||
| if (dependency.getVersion() == null && data.getFileVersion() != null) { | ||
| final DependencyVersion version = DependencyVersionUtil.parseVersion(data.getFileVersion(), true); | ||
| if (dependency.getVersion() == null && data.getProductVersion() != null) { |
Collaborator
Author
There was a problem hiding this comment.
note: See the mention of Priority 3 in the behavior change of the PR description for additional information.
Collaborator
|
Great analysis! thank you. I completely agree that we should limit the VersionFilterAnalyzer to just Java/JAR files - this is the only place we really get a vast amount of evidence that needed to be filtered. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description of Change
Witnessed behavior change
Commit fix: #8140 fix version resolution
1fb840ba7d94cc894f5a4fb92dfa8ed2f384adfdWith the AssemblyAnalyzer version resolution commit, the shared dll in #8140 is now resolved as being in version
1.7.0instead of1.700.22.46903.This commit allow to raise CVE-2023-36414
Commit fix: #8140 hint azure_identity_library_for_.net
9f58d2f2c4fcde3c8e3df36837efcee10f972234This additional hint make DependencyCheck report CVE-2024-29992 on the shared dll in #8140
Business logic
This PR proposes to fix the
AssemblyAnalyzerversion resolution at priority levels 2, 3 & 4.Priority level 1 resolution remains unchanged. In case ProductVersion and FileVersion both match on the first 3 parts, the common pattern between both versions is used as the dependency version.
Priority level 2 adds a stronger filtering mechanism to prevent picking one of the ProductVersion or FileVersion as the dependency version in case the less specified version contradicts the longer one.
As an example:
parsed
ProductVersion = 1.2& parsedFileVersion = 1.2.13.0will resolves the dependency version to1.2.13.0as1.2is included in the longer one - not a change with the current implementation.parsed
ProductVersion = 1.2.13.0& parsedFileVersion = 1.2will resolves the dependency version to1.2.13.0as1.2is included in the longer one - not a change with the current implementation.parsed
ProductVersion = 1.7.0& parsedFileVersion = 1.700.22.46903will not resolve the dependency version as there is a contradiction at minor version level between1.7&1.700- change with the current implementation which set the longer version.Priority level 3 will pick the
ProductVersionif exists and can be parsed - change with the current implementation which would pick the parsedFileVersion. This aligns with our current evidence confidence where ProductVersion has a higher confidence than FileVersion.Priority level 4 will pick parsed
FileVersionif noProductVersioncould be parsed - change with the current implementation which would pick the parsedProductVersionat this priority level.Finally, if nothing before could help us set the dependency version, we do not set it and leave the evidences, which do not get filtered by the VersionFilterAnalyzer as now dependency version is set. - not a change with the current implementation
Related issues
Have test cases been added to cover the new functionality?
yes, the added test covers the
AssemblyAnalyzerdependency version resolution, with its input strictly being exactly what was provided into the method during real execution in debug mode.Test snippet used to execute the CLI in e2e
In
AppTest, withmy-secrets.propertiescontaining my NVD API Key and OssIndex credentials:Additional notes identified during the investigation
Thanks to @chadwilson for a first investigation which already located the root of the issue
I identified additional room of improvements/analysis into the product, and would like to share to see if we agree to pursue some additional improvements.
AssenblyAnalyzerdependency version resolution refactoringThe code holding the logic to decide to set a version could be refactored to improve clarify and reveal the business logic. I did not do it in this change on purpose as I want to emphasis the behavior change in this PR. If the approach of the change is approved, I am planning to come with an additional refactoring PR, looking for an easier to read logic.
VersionFilterAnalyzerresponsibilityAs stated in this comment the
VersionFilterAnalyzerremoves version evidences if a version is set, unless evidence is a hint.The JavaDoc shows the intention behind the version analyzer:
It is actually covering much more than that as it will inspect all dependencies. Is this JavaDoc still showing the true intention of this analyzer, in such case we have a bug, or is the doc obsolete and to be updated?
I believe we could consider narrowing the scope of the VersionFilterAnalyzer to be specifically dedicated to jar files, as intended by the JavaDoc. This would increase the number of false positive, but reduce the risk of false negatives (and I believe with the purpose of DependencyCheck, it is better to have false positives than false negatives). Please note this was first considered as the fix in this PR, which has the same effect as the dependency version resolution, but I did not pick this route in fear of raising the amount of false positive while the assembly dependency version resolution logic was already looking broken, it may still improve some other scenarios
CPEAnalyzerintegration issue withVersionFilterAnalyzerand owner of the decision to rely on the dependency version and evidencesIn the
VersionFilterAnalyzer, if a dependency version is set, then we remove all version evidences not coming from an hint.Later in the analysis, we enter the
CPEAnalyzerwhich has a methodconsiderDependencyVersion(Dependency dependency, String vendor, String product, Confidence confidence, final Set<IdentifierMatch> collected)which decides to rely on version evidences in some cases even if a dependency version is set, while all the evidences got removed by theVersionFilterAnalyzer. It looks like we have 2 pieces of code at 2 different locations trying to have the same responsibility and they don't interact very well between each other 🤔CPEAnalyzerdecision to rely on the dependency version or evidences seems to have a case sensitivity bugIn
CPEAnalyzer, the methodconsiderDependencyVersion(Dependency dependency, String vendor, String product, Confidence confidence, final Set<IdentifierMatch> collected)has the following code snippet:While debugging in this snippet, for this specific case, a
"Azure".contains("azure")ends up being made, which evaluatesuseDependencyVersiontofalse, which makes theCPEAnalyzerdecides to not base itself on the dependency version but the version evidences (who were wiped out by theVersionFilterAnalyzer). I did not pursue a fix in this area as in this specific case, the analyzer still decides to rely on evidences for another reason afterwards. It might be interesting to consider an case insensitive comparison.