CVE-2026-12816 Overview
CVE-2026-12816 affects Bouncy Castle for Java before version 1.85 and Bouncy Castle for Java LTS before 2.73.12. The vulnerability resides in the IESEngine stream-mode implementation, where a length-dependent key derivation function (KDF) split allows Message Authentication Code (MAC) forgery. The flaw is classified under [CWE-354] Improper Validation of Integrity Check Value. An attacker with a single known-plaintext observation can recover the MAC key of shorter messages and forge ciphertext plus tag pairs that the recipient accepts as authentic.
Critical Impact
Attackers can forge authenticated ciphertexts under static-key IESEngine stream mode, breaking integrity guarantees for ECIES-derived deployments.
Affected Products
- Bouncy Castle for Java before 1.85
- Bouncy Castle for Java LTS before 2.73.12
- Applications using IESEngine in static-key stream mode (IES/ECIES/DHIES without a backing block cipher)
Discovery Timeline
- 2026-08-03 - CVE-2026-12816 published to NVD
- 2026-08-04 - Last updated in NVD database
Technical Details for CVE-2026-12816
Vulnerability Analysis
The vulnerability affects IESEngine when used in stream mode without a backing block cipher. In stream mode, the KDF output is split into two keys: K1 (the keystream used to XOR with the plaintext) and K2 (the MAC key). The ephemeral-sender path used a fixed prefix layout, taking K2 from the beginning and K1 from the remainder. The static-key initialization path used the inverse layout, taking K1 first and placing K2 at a message-length-dependent offset. Because the static-key mode reuses the same KDF input for every message, the derived material is deterministic across messages under one key pair.
Root Cause
The static-key init(boolean, CipherParameters, CipherParameters, CipherParameters) entry point omits an ephemeral component, so the KDF input is identical for every message. Combined with the length-dependent split, K2 sits at an offset behind K1 in the derived stream. An attacker who recovers K1 for one message through a known-plaintext pair obtains plaintext XOR ciphertext, which exposes the region of the KDF output that later serves as K2 for any shorter message. The MAC key is effectively covered by the same keystream used for encryption.
Attack Vector
The attack requires network-accessible ciphertexts and one known-plaintext pair. After recovering K1, the attacker computes the MAC key of any shorter message and generates a forged ciphertext plus valid tag. The recipient accepts the forgery without detection. Confidentiality of static-key stream mode is also broken because the keystream repeats across messages, forming a many-time pad.
/**
* Set up for use with stream mode, where the key derivation function
* is used to provide a stream of bytes to xor with the message.
* <p>
* <b>Security note:</b> when this engine is initialised with static keys on both sides (the
* {@link #init(boolean, CipherParameters, CipherParameters, CipherParameters)} entry point, which
* supplies no ephemeral component) the key-derivation input is the same for every message, so the
* stream-mode keystream is identical from message to message - encrypting more than one message
* under a given key pair is a many-time pad and leaks plaintext relationships. Use the ephemeral
* sender-key initialisation (the standard ECIES mode) for messages that must remain confidential;
* the static-static mode is effectively deterministic encryption.
* </p>
*
* @param agree the key agreement used as the basis for the encryption
* @param kdf the key derivation function used for byte generation
*/
// Source: https://github.com/bcgit/bc-java/commit/6d9e4bbaee9409713ada167e5f901554cbb084ac
The patch enforces the fixed K2-first layout on both paths, so the MAC key is never covered by the keystream.
Detection Methods for CVE-2026-12816
Indicators of Compromise
- Repeated ciphertexts of identical length under the same static key pair, indicating deterministic encryption reuse.
- Successful MAC verification on ciphertexts that were not produced by legitimate senders.
- Application logs referencing IESEngine initialization via the four-argument init method with no ephemeral parameters.
Detection Strategies
- Audit application code and dependencies for direct or transitive use of org.bouncycastle.crypto.engines.IESEngine in stream mode.
- Identify calls to IESEngine.init(boolean, CipherParameters, CipherParameters, CipherParameters) where the ephemeral parameter is absent.
- Inventory Bouncy Castle versions across Java build manifests to flag versions earlier than 1.85 or LTS 2.73.12.
Monitoring Recommendations
- Track cryptographic library versions in Software Bill of Materials (SBOM) tooling and alert on outdated Bouncy Castle artifacts.
- Monitor authentication failures and integrity check anomalies in services that decrypt ECIES payloads.
- Log ciphertext lengths and sender identifiers to identify anomalous variance patterns consistent with forgery attempts.
How to Mitigate CVE-2026-12816
Immediate Actions Required
- Upgrade Bouncy Castle for Java to version 1.85 or later, or Bouncy Castle for Java LTS to 2.73.12 or later.
- Replace static-key IESEngine stream-mode usage with the ephemeral sender-key initialization used by standard ECIES.
- Rotate long-term ECIES key pairs that were used with the static-static stream mode.
Patch Information
The fix is committed in the Bouncy Castle GitHub repository. Both the ephemeral and static-key paths now use the fixed K2-first layout, ensuring the MAC key sits before the keystream in the derived output. The ephemeral ECIES wire format is unchanged. Ciphertexts produced by earlier versions in static-static stream mode will no longer decrypt after the update. Additional context is available in the CVE-2026-12816 wiki entry.
Workarounds
- Switch to IESEngine configurations with a backing block cipher rather than raw stream mode.
- Use ephemeral sender keys via the standard ECIES initialization for any message that must remain confidential or authenticated.
- Avoid encrypting more than one message under a single static key pair when stream mode cannot be replaced immediately.
# Maven dependency update example
mvn versions:set-property -Dproperty=bouncycastle.version -DnewVersion=1.85
mvn versions:use-latest-versions -Dincludes=org.bouncycastle:bcprov-jdk18on
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

