Issue
Java Assess records only the first route visited for the following vulnerabilities.
Assess rules: Insecure Hash Algorithms and Insecure Encryption Algorithms.
Cause
Using https://github.com/SasanLabs/VulnerableApp as an example:
Assess will report a vulnerability if and only if we see certain method calls we label as “sinks” for specific vulnerabilities. For these two vulnerabilities, crypto-bad-ma
and crypto-bad-cipher
the sinks are Ciper.getInstance(String)
and MessageDigest.getInstance(String)
which are both called downstream from the same method.
org.sasanlabs...JWTAlgorithmKMS#loadAsymmetricAlgorithmKeys()
If we take a look at each of these routes that are visited we see this
JWTAlgorithmKMS jwtAlgorithmKMS = new JWTAlgorithmKMS();
Each route creates their own JWTAlgorithmKMS
object. The reason Contrast Assess is behaving correctly here, is that the constructor for this object lazily instantiates this insecurekey
on first request.
private static volatile boolean initDone = false;
public JWTAlgorithmKMS() {
// ensures thi object is only initialized once
if (!initDone) {
synchronized (MUTEX) {
if (!initDone) {
// this calls the vulnerable loadAsymmetricAlgorithmKeys()
initialize();
initDone = true;
}
}
}
}
Each request shares a global key that gets initialized lazily. The first request is responsible for initializing the key. The intialize()
method calls loadAsymmetricAlgorithmKeys()
which calls the underlying Ciper.getInstance(String)
and MessageDigest.getInstance(String)
under the hood - triggering this vulnerability to be reported in Contrast. But this method is only called once during the first time this object is created (due to the logic in their constructor) and therefore we'll never trigger the vulnerabilities after the first request.
This is why these vulnerabilities are only associated with the first route that is exercised on each app run, because that is the only time this vulnerable method call is actually made.