astropod Contact Us sign in

A Quick Look Back at Bouncy Castle Java 1.85 Patched 32 CVEs, Including a Critical Unvalidated Diffie-Hellman Key Flaw

Published on gastropod.io on 09-01-2026

A Quick Look Back at Bouncy Castle Java 1.85 Patched 32 CVEs, Including a Critical Unvalidated Diffie-Hellman Key Flaw

Tags: vulnerability intelligence, software supply chain security, maven, java, cryptography

Bouncy Castle's July 2026 release is worth a look. A library that's typically inherited rather than purposefully chosen patched a critical crypto break, fixed an AEAD oracle, and re-patched a repeat of a bug it already claimed to fix, all in one release. That combination is what turns a routine version bump into something to look at closer.

background

The Bouncy Castle team released Java 1.85 on July 28, 2026, and the release notes list fixes for 32 separate CVEs spanning the library's ASN.1, CMS, OpenPGP, PKIX, keystore, and provider modules. No single flaw drove a press cycle. The volume is the story: a library that many Java applications use, directly quietly closed 32 distinct security gaps in one release, and almost none of the affected downstream projects will even be aware that they were vulnerable unless they are actively checking the exact version they run.

The most severe of the batch is CVE-2026-59650, a 9.1 CVSS flaw in the MTI/A0 Diffie-Hellman agreement implementation. The code exponentiates a peer-supplied public value without validating it first, which opens the door to invalid-parameter attacks: a malicious peer can send a crafted value chosen from a small subgroup, and the resulting shared secret leaks information about the victim's private key with each exchange. The fix landed in bcprov-jdk18on and bcprov-lts8on alongside the 1.85 and 2.73.12 releases.

CVE-2026-58061 hits a different failure profile.... The CCM family of authenticated encryption modes in Bouncy Castle for Java writes decrypted plaintext into the caller's output buffer before it verifies the authentication tag. On a failed tag check, the library throws InvalidCipherTextException, but the unverified plaintext already sits in the buffer the caller passed in. NIST SP 800-38C section 6.2 requires the opposite order: verify, then release. An attacker who can observe that buffer after a failed check gets an unauthenticated decryption oracle against forged ciphertext, effectively turning an AEAD mode into plain CTR mode for attack purposes.

One entry in the list is a repeat of an issue they already fixed once.... CVE-2026-0636, patched in Bouncy Castle 1.84 back in April, fixed an LDAP filter injection in LDAPStoreHelper inside the library's modern provider modules. CVE-2026-59652, fixed in this release, is the same injection class in a second, legacy jdk1.4 code path of the same class that the earlier fix did not correct. A team that upgraded to 1.84 specifically to close the April LDAP injection and stopped tracking Bouncy Castle CVEs after that would have still been exposed three more months with a second copy of the same bug.

why should you care?

Bouncy Castle rarely appears as a direct dependency declaration. It arrives as a transitive artifact, pulled in by connector frameworks, identity platforms, and infrastructure projects that need TLS, PGP, or ASN.1 handling and did not want to write that code themselves. Apache Hadoop's build resolves it for cryptographic support, and a single pull request had to raise the version across Hadoop's dependency tree to pick up fixes for five separate CVEs at once. Hadoop's own maintainers did not choose Bouncy Castle for its own sake; they inherited it through the libraries that depend on it.

That is an inventory problem this release creates for anyone running Java services: knowing which of your builds actually resolved a Bouncy Castle artifact between 1.74 and 1.85, at the specific module and version, without relying on someone remembering that a connector library or a logging bridge happens to bundle it.

how can gastropod.io can help in these situations?

Gastropod tracks every Maven artifact it proxies by PURL and sha256 digest, not by package name alone, so it distinguishes a patched 1.85 build from the vulnerable 1.80 or 1.83 builds sitting in the same dependency tree, and it does the same for the FIPS and LTS variants that carry their own version numbers. An OSV match against bcprov-jdk18on, bcpkix-jdk18on, or bcpg-jdk18on in the affected range surfaces every service that pulled it in, directly or transitively, through the blast-radius graph, and a CycloneDX SBOM generated on demand shows exactly where in the tree it sits. Details on how that correlation works are on the product page.

Sources:

← news