CVE-2026-85515
NoneCVSS
—
EPSS
0.2%
Published
Oct 3, 2026
CISA due date
—
Cloudanix analysis
A cryptography library used in many Java programs could silently accept incomplete or altered encrypted messages, allowing recipients to receive data that should have been rejected as untrustworthy.
- Exploitation
- Remote Unauthenticated
- Attacker needs
- None
- Complexity
- Low
- Impact
- Data Tampering
- Component
- Library
- Class
- Cryptographic Weakness
- Remediation
- Upgrade
- Effort
- Medium
- Patch risk
- Low
What it actually does
Truncated OpenPGP encrypted messages are accepted without error reporting or integrity verification on SEIPD v1 and certain AEAD paths, allowing release of partially authenticated plaintext while silently dropping subsequent packets.
Why it matters to the business
Organizations relying on Bouncy Castle OpenPGP handling risk accepting tampered or incomplete encrypted data as valid, potentially undermining confidentiality and integrity protections in messaging or file encryption workflows; the issue affects multiple product lines including standard, LTS, and FIPS editions.
How an attack unfolds
An attacker crafts a truncated OpenPGP message (with unchanged outer length fields) and delivers it to a vulnerable Bouncy Castle consumer; the library's stream handling discards the truncation, skips integrity checks on the SEIPD v1 path or fails to validate total length on AEAD, and returns the decrypted content without raising an error or invoking verify().
How to fix it
Upgrade Bouncy Castle for Java to 1.86 or newer; for LTS use 2.73.13 or newer; for BC-FJA use bcpg-fips 1.0.14, 2.0.14.1, or 2.1.14 as appropriate. Recompile and redeploy dependent applications after the library update.
How to confirm the fix worked
Confirm the Bouncy Castle version string matches a fixed release, then replay known truncated test vectors to verify that EOF conditions now produce IOException or integrity failures instead of silent plaintext release.
Typical attack path
- Identify a target application using vulnerable Bouncy Castle OpenPGP APIs
- Generate or intercept an encrypted message and truncate it at a reachable offset that bypasses length checks
- Transmit the malformed message to the recipient
- Observe acceptance of the resulting plaintext without integrity exceptions or signature validation
How to detect it
Search application and library logs for unexpected EOFException handling around PGP decryption streams or OpenPGPMessageInputStream, and review any code paths that consume PGPEncryptedData without explicitly calling verify().
What your security team should do
- Immediately inventory all Java applications and libraries for Bouncy Castle versions prior to the fixed releases
- Prioritize patching of any FIPS or LTS deployments still on the AEAD-vulnerable code paths
- Update build and dependency manifests to enforce the corrected versions and schedule regression testing of OpenPGP message handling
- Review downstream dependents and ecosystem packages that bundle older Bouncy Castle releases
The record
In Bouncy Castle for Java before 1.86, a truncated OpenPGP encrypted message was accepted with no error reported, and on the SEIPD version 1 path with no integrity check performed at all. RFC 9580 sec. 13.7 permits an implementation to release the cleartext of the fully authenticated chunks when streaming but requires it to indicate a clear error as soon as the truncation is detected, and to report suspect integrity when it discovers malleable ciphertext. The truncation was detected and then discarded: when a message is truncated but the length field of the enclosing packet is left unchanged, BCPGInputStream.PartialInputStream raises an EOFException for the missing ciphertext, and BCPGInputStream.nextPacketTag() reports an EOFException as a clean end of message, so the packet stream above it stopped as though no packets remained. On the AEAD path (SEIPD version 2 and the version 5 AEAD packet), when the literal data packet ended on an AEAD chunk boundary and the consumer read in increments smaller than one chunk, the look-ahead for the packet after the literal triggered the truncated chunk read, so BcAEADUtil and JceAEADUtil never reached the trailing message tag of sec. 5.13.2 that authenticates the total plaintext length; the caller received the plaintext of the fully authenticated chunks, every packet following the literal was silently dropped, and no exception was raised, so a signed and encrypted message read back as a well-formed unsigned one. Every byte released on that path remained individually authenticated, making this a missing truncation error rather than a forgery, and it is a residual of CVE-2026-12817, which closed the same outcome for an attacker who corrects the outer packet length. On the SEIPD version 1 path the consequence was more serious: IntegrityProtectedInputStream verifies the modification detection code from close(), and reached close() only by closing itself when a read of it returned -1, which a truncated message never produces, so PGPEncryptedData.verify() never ran and the recipient was handed CFB-decrypted plaintext on which no integrity check of any kind had been performed. Measured on a message truncated into that shape, 136 distinct single-byte modifications of the ciphertext produced accepted, altered plaintext with no exception raised. Reachability is a property of the message rather than of attacker-supplied input: the AEAD shape held for 3 of 131 consecutive payload lengths measured, and the SEIPD version 1 shape for one payload length in sixteen, at a truncation offset that did not move with the payload length. The low-level API is unaffected, a caller that invokes PGPEncryptedData.verify() directly getting the check regardless, as are consumers reading in increments of a whole AEAD chunk or more. The AEAD decryption streams now re-throw such an EOFException as a plain IOException, which nextPacketTag() does not launder; OpenPGPMessageInputStream.close() now closes its layer's integrity-protected stream itself rather than relying on that stream having seen the end of its data; and IntegrityProtectedInputStream.close() was made idempotent, as java.io.Closeable requires, which that depends on, since the stream is genuinely closed twice on the ordinary path and PGPEncryptedData.verify() consumes the digest state behind it and cannot be run a second time. This issue also affects Bouncy Castle for Java LTS before 2.73.13, on the AEAD route only, as that edition does not ship the high-level OpenPGP API the SEIPDv1 route runs through. It also affects Bouncy Castle for Java FIPS (BC-FJA) before bcpg-fips 1.0.14 (1.0.X series), 2.0.14.1 (2.0.X series) and 2.1.14 (2.1.X series), on the AEAD route only, as those editions do not ship the high-level OpenPGP API.
Affected packages
| Ecosystem | Package | Introduced | Fixed |
|---|
Related vulnerabilities
- CVE-2022-30267 Emerson Ovation was found to have no authentication of firmware signing and relies on an… CWE-345
- CVE-2026-76894 CKAN MCP Server is a tool for querying CKAN open data portals. CWE-345
- CVE-2026-121545 Dreeve before 5.8.0 contains a missing authentication vulnerability in… CWE-345
- CVE-2026-119731 Munshi (by Petpooja) before 2026-06-30 contained a payment bypass vulnerability in its… CWE-345
- CVE-2026-103310 The PayHere Payment Gateway WordPress plugin from 2.4.0 through 2.4.5 does not verify the… CWE-345
- CVE-2026-120317 http4k from 4.9.10.0 before 6.60.0.0 contains a missing integrity check vulnerability… CWE-345
- CVE-2026-63115 ActivityPub is a multi-tenant ActivityPub server for Ghost, built with Fedify. CWE-345
- CVE-2026-119289 Zuke is a code-first, strongly typed build automation system for Deno. CWE-345