previously prevented exploit now possible with JDK 18

Rick Hillegas rick.hillegas at
Wed Nov 3 17:07:00 UTC 2021

Thanks for your detailed comments, Sean. We agree wholeheartedly that 
being signed and being trusted/valid are two separate concepts. The JDK 
wisely punts the issue of trust to the application developer. As I 
understand it, we disagree about the following points:

1) Is the signedness of a jar an immutable fact or is it just an 
opinion? I think that it is an immutable fact, measured by whether the 
jar's manifest contains certain stereotypical files. You maintain that 
it is an opinion which can shift incompatibly between JDK releases.

2) Should the JDK continue to raise an exception when loading classes 
from clearly compromised jars?

3) Are javadoc and a release note adequate defenses against an exploit 
which will surface when a mission-critical application upgrades to a JDK 
containing the work on ?

Here's how I see it:

a) A jar doesn't cease to be signed when its signer goes to jail and 
authorities revoke the signing certificate.

b) A jar doesn't cease to be signed because someone pokes malware into 
it and breaks the hash.

c) A jar doesn't cease to be signed because serious people distrust its 
old, shoddy cryptography.

In all of these cases, trust has diminished. But the jar is still signed.

Note that the emphatic deprecation of the SecurityManager affects your 
comments below.


On 11/2/21 11:34 AM, Sean Mullan wrote:
> Hello Rick,
> It is behaving as expected. Let me explain in more detail.
> First, loading a signed JAR off the classpath only verifies the
> signature and digests of the JAR file. It does not validate the signer's
> certificate chain or determine if the signer is trusted. The JarFile API
> class description includes this warning [1]:
> "Please note that the verification process does not include validating
> the signer's certificate. A caller should inspect the return value of
> JarEntry.getCodeSigners() to further determine if the signature can be
> trusted."
> Some frameworks such as Web Start have this additional checking
> built-in. Or, if you run your code with a Security Manager, then
> additional steps will be performed at run-time to check that the code is
> signed and that the signer's public key is trusted before granting
> permissions to that code.
> If you don't perform these additional steps, then the JAR can be
> modified without detection. For example, the signature related files
> could be removed from the JAR (thus making it an unsigned JAR), or the
> JAR could be modified and then re-signed with a different key. In either
> of these cases, the JVM would load the JAR without any exception.
> It is also possible that a JAR signed with a weak or broken algorithm 
> (such as MD5 or SHA-1) could be modified without detection.
> This is why the JDK implementation supports several security
> properties which are used to disable cryptographic algorithms and
> protocols that are weak or broken. This provides out-of-the-box security
> and is important to safeguard against crypto algorithms that inevitably
> become weaker over time. One of these properties is
> "jdk.jar.disabledAlgorithms". The specification of this property defines
> the behavior if a signed JAR file is signed with an algorithm that is
> disabled [2]:
> "JARs signed with any of the disabled algorithms or key sizes will be
> treated as unsigned."
> The JDK determined after step 1 of the JAR verification process [3] that
> the JAR was signed with SHA-1, and therefore stopped further processing.
> You may ask why we don't throw an Exception in this case. Although this
> was considered, the compatibility risk was too high. These
> restrictions are nearly always backported to earlier JDK update
> releases. Throwing an Exception would be too high of a risk for
> applications that happen to load signed JARs off the classpath but don't
> otherwise behave any differently. Our primary focus is to protect
> applications that verify that the code is signed by someone they trust.
> Consider updating and re-signing your signed jar with a stronger, 
> non-broken algorithm such as SHA-2. SHA-2 is the default digest 
> algorithm used by jarsigner when the -digestalg option is not specified.
> I hope this information is useful. I do think this is an area where our
> javadocs and guides could be improved to provide more information about
> how signed JARs are verified including more details on the behavior of
> the JDK implementation with respect to disabled algorithms. We will be
> working to try to improve the docs for JDK 18.
> --Sean
> [1]
> [2]
> [3]
> On 10/28/21 3:14 PM, Rick Hillegas wrote:
>> As a canary in the mineshaft, I built and tested Apache Derby with the
>> recent build 18-ea+20-1248 of Open JDK 18. I tripped across the
>> following issue when running Derby's regression tests. The problem is
>> explained in more detail at
>>, where a simple repro
>> (DERBY_7126_A) can be found. The problem is almost surely the result of
>> work done on (Disable
>> SHA-1 Signed JARs).
>> Under previous versions of the JDK, the JVM would raise an error if you
>> tried to load a class from a jar file which had been signed with SHA-1
>> but later hacked by inserting malware via "jar -uf". This was the error:
>>     SHA1 digest error for $corruptedJarFileName
>> However, under JDK 18 the hacked class loads, no error is raised, and
>> the malware can now be executed. I was surprised that a previously
>> prevented exploit now works. I think it would be better if the JVM still
>> refused to load the hacked class even though SHA-1 has been deprecated.
>> Thanks,
>> -Rick

More information about the security-dev mailing list