Description
In Bouncy Castle for Java before 1.86, the high-level OpenPGP API accepted a data signature made by a signing subkey whose Subkey Binding signature carried no embedded Primary Key Binding (cross-certification) signature, in the case where that binding omits a Key Flags subpacket. RFC 9580 sec. 5.2.1.8 and sec. 10.1.3 require the embedded Primary Key Binding signature on any subkey that can issue signatures; it is the subkey's own statement that it belongs to the primary key it is bound under. OpenPGPCertificate resolved the subkey's key flags two different ways. isSigningKey() goes through getKeyFlags() and getApplyingSubpacket(), which falls back to the primary key's direct-key or primary User ID self-signature when the binding signature omits the subpacket, so the subkey inherited the primary's SIGN_DATA and counted as signing-capable; verifyEmbeddedPrimaryKeyBinding(), which enforces the requirement, reads the binding signature's own hashed subpackets, found no SIGN_DATA there, and returned early as a non-signing key without ever demanding the back signature. The same subkey was therefore signing-capable - so its signatures were attributed to the certificate and OpenPGPSignature.OpenPGPDocumentSignature.isValid() returned true - while being exempt from cross-certification, where GnuPG refuses the identical certificate and message. An attacker needs only the victim's public signing subkey, which is public material: they bind it to their own primary key with a Subkey Binding signature they are able to make, carrying no Key Flags and no embedded Primary Key Binding signature, which they cannot make without the subkey's private key, and a relying party verifying one of the victim's genuinely signed messages against that certificate is told the signature is valid and given the attacker's certificate as its issuer. Because a certificate's User IDs are self-asserted, a verifier that pins on the subkey's fingerprint or key ID while taking the identity from the enclosing certificate reports a real signature under an attacker-chosen identity. This is misattribution of a genuine signature rather than forgery of a new one: no private key is recovered, and the signature must be one the grafted subkey actually made. The low-level PGPSignature / PGPPublicKeyRing API performs no binding checks by design and is unaffected. Key Flags are a statement about the key the carrying signature refers to (RFC 9580 sec. 5.2.3.29), so a subkey no longer inherits them from the certificate-wide signatures of the primary key: a Subkey Binding signature that omits the subpacket now leaves the subkey with no capabilities rather than the primary's, which makes the flags the cross-certification check consults the same flags every other decision consults. Preferences and the other subpackets a direct-key signature carries are inherited as before, and the primary key itself, whose flags legitimately come from its own direct-key or User ID self-signature, is unaffected.
Published: 2026-10-03
Score: 8.2 High
EPSS: n/a
KEV: No
Impact: Misattribution of signatures leading to authenticity compromise
Action: Patch Bouncy Castle
AI Analysis

Impact

In Bouncy Castle Java before 1.86, the high‑level OpenPGP API accepts a data signature created with a signing subkey whose binding signature omits the required embedded Primary Key Binding cross‑certification when no Key Flags subpacket is present. The API incorrectly treats the subkey as signing‑capable, allowing the signature to be considered valid and attributed to the certificate, while the lack of cross‑certification means the binding was not verified. An attacker can exploit this by taking a victim’s publicly available signing subkey, binding it to their own primary key with a Subkey Binding signature that carries no Key Flags and no embedded Primary Key Binding, and then presenting that certificate to a verifier that uses the vulnerable API. The verifier will accept the signature as legitimate and report the attacker’s identity as the signer, resulting in misattribution of the signature without requiring possession of the private key. The vulnerability therefore undermines authenticity and trust in signed content, potentially facilitating impersonation and fraud.

Affected Systems

Any deployment of Bouncy Castle for Java with a library version older than 1.86 that relies on the high‑level OpenPGP API for signature verification is affected. This includes applications that use Bouncy Castle’s OpenPGPCertificate and OpenPGPSignature OpenPGPDocumentSignature classes. The low‑level PGPSignature and PGPPublicKeyRing APIs are not impacted.

Risk and Exploitability

The CVSS score of 8.2 classifies this as a high‑severity flaw. Because the exploit requires only the victim’s public signing subkey and can be carried out by crafting a Subkey Binding signature that omits required subpackets, the vulnerability is technically exploitable against any system that employs the vulnerable API. The EPSS score is not available, but the lack of coverage in the CISA KEV catalog does not diminish the intrinsic risk. An attacker’s ability to hijack a legitimate signature and misattribute it to a forged identity introduces a serious authenticity risk that can be leveraged for phishing, fraud, or denial of trust in software distributions.

Generated by OpenCVE AI on October 3, 2026 at 09:20 UTC.

Remediation

No solution or workaround provided in the CVE record.

OpenCVE Recommended Actions

  • Upgrade Bouncy Castle to version 1.86 or later.
  • If an immediate upgrade is not possible, replace use of the high‑level OpenPGP API with the low‑level PGPSignature/PGPPublicKeyRing API, which performs no binding checks and is unaffected.
  • Add an application‑level check that verifies any signing subkey carries an embedded Primary Key Binding signature before accepting the signature.

Generated by OpenCVE AI on October 3, 2026 at 09:20 UTC.

Tracking

Sign in to view the affected projects.

Advisories

No advisories yet.

History

Sat, 03 Oct 2026 08:45:00 +0000

Type Values Removed Values Added
Description In Bouncy Castle for Java before 1.86, the high-level OpenPGP API accepted a data signature made by a signing subkey whose Subkey Binding signature carried no embedded Primary Key Binding (cross-certification) signature, in the case where that binding omits a Key Flags subpacket. RFC 9580 sec. 5.2.1.8 and sec. 10.1.3 require the embedded Primary Key Binding signature on any subkey that can issue signatures; it is the subkey's own statement that it belongs to the primary key it is bound under. OpenPGPCertificate resolved the subkey's key flags two different ways. isSigningKey() goes through getKeyFlags() and getApplyingSubpacket(), which falls back to the primary key's direct-key or primary User ID self-signature when the binding signature omits the subpacket, so the subkey inherited the primary's SIGN_DATA and counted as signing-capable; verifyEmbeddedPrimaryKeyBinding(), which enforces the requirement, reads the binding signature's own hashed subpackets, found no SIGN_DATA there, and returned early as a non-signing key without ever demanding the back signature. The same subkey was therefore signing-capable - so its signatures were attributed to the certificate and OpenPGPSignature.OpenPGPDocumentSignature.isValid() returned true - while being exempt from cross-certification, where GnuPG refuses the identical certificate and message. An attacker needs only the victim's public signing subkey, which is public material: they bind it to their own primary key with a Subkey Binding signature they are able to make, carrying no Key Flags and no embedded Primary Key Binding signature, which they cannot make without the subkey's private key, and a relying party verifying one of the victim's genuinely signed messages against that certificate is told the signature is valid and given the attacker's certificate as its issuer. Because a certificate's User IDs are self-asserted, a verifier that pins on the subkey's fingerprint or key ID while taking the identity from the enclosing certificate reports a real signature under an attacker-chosen identity. This is misattribution of a genuine signature rather than forgery of a new one: no private key is recovered, and the signature must be one the grafted subkey actually made. The low-level PGPSignature / PGPPublicKeyRing API performs no binding checks by design and is unaffected. Key Flags are a statement about the key the carrying signature refers to (RFC 9580 sec. 5.2.3.29), so a subkey no longer inherits them from the certificate-wide signatures of the primary key: a Subkey Binding signature that omits the subpacket now leaves the subkey with no capabilities rather than the primary's, which makes the flags the cross-certification check consults the same flags every other decision consults. Preferences and the other subpackets a direct-key signature carries are inherited as before, and the primary key itself, whose flags legitimately come from its own direct-key or User ID self-signature, is unaffected.
Title OpenPGP data signature accepted from a signing subkey without cross-certification
Weaknesses CWE-345
CWE-347
References
Metrics cvssV4_0

{'score': 8.2, 'vector': 'CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N/U:Amber'}


Subscriptions

No data.

cve-icon MITRE

Status: PUBLISHED

Assigner: bcorg

Published:

Updated: 2026-10-03T08:39:07.997Z

Reserved: 2026-08-08T00:06:06.982Z

Link: CVE-2026-71887

cve-icon Vulnrichment

No data.

cve-icon NVD

Status : Received

Published: 2026-10-03T09:17:05.067

Modified: 2026-10-03T09:17:05.067

Link: CVE-2026-71887

cve-icon Redhat

No data.

cve-icon OpenCVE Enrichment

Updated: 2026-10-03T09:30:19Z

Weaknesses
  • CWE-345

    Insufficient Verification of Data Authenticity

  • CWE-347

    Improper Verification of Cryptographic Signature