bouncycastle — security advisory
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
- Products
- bouncycastle
- Affected versions
- 1.72-2, 1.77-1, 1.80-1, 1.80-2, 1.80-3, 1.86-1
- Fixed versions
- 1.86-1
- CVEs
- CVE-2026-71887
- Confirmed fixed CVEs
- Not specified
- Updated in this feed
- 28 Oct 2026, 03:41 UTC · Revision 1
Source evidence
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
osv:DEBIAN-CVE-2026-71887
bouncycastle
Fixed versions: Not specified
bouncycastle
Fixed versions: Not specified
bouncycastle
Fixed versions: 1.86-1
Complete source record
{
"id": "50449f6b2bd3f4cb97b9c148f2f78daea7db54c9d70dc288f374d09d810fbe91",
"url": "https://osv.dev/vulnerability/DEBIAN-CVE-2026-71887",
"method": "structured",
"payload": {
"kind": "advisory",
"title": "DEBIAN-CVE-2026-71887",
"summary": "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",
"evidence": "osv:DEBIAN-CVE-2026-71887",
"products": [
{
"name": {
"value": "bouncycastle",
"evidence": "/affected/0/package/name"
},
"prerequisites": [],
"fixed_versions": [],
"affected_versions": [
{
"value": "1.72-2",
"evidence": "/affected/0/versions"
},
{
"value": "1.77-1",
"evidence": "/affected/0/versions"
},
{
"value": "1.80-1",
"evidence": "/affected/0/versions"
},
{
"value": "1.80-2",
"evidence": "/affected/0/versions"
},
{
"value": "1.80-3",
"evidence": "/affected/0/versions"
},
{
"value": "1.86-1",
"evidence": "/affected/0/versions"
}
]
},
{
"name": {
"value": "bouncycastle",
"evidence": "/affected/1/package/name"
},
"prerequisites": [],
"fixed_versions": [],
"affected_versions": [
{
"value": "1.80-3",
"evidence": "/affected/1/versions"
},
{
"value": "1.86-1",
"evidence": "/affected/1/versions"
}
]
},
{
"name": {
"value": "bouncycastle",
"evidence": "/affected/2/package/name"
},
"prerequisites": [],
"fixed_versions": [
{
"value": "1.86-1",
"evidence": "/affected/2/ranges"
}
],
"affected_versions": [
{
"value": "1.80-3",
"evidence": "/affected/2/versions"
}
]
}
],
"severity": "high",
"structured": {
"id": "DEBIAN-CVE-2026-71887",
"aliases": [
"DEBIAN-CVE-2026-71887"
],
"metrics": [
{
"type": "CVSS_V4",
"score": "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/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:Amber"
}
],
"affected": [
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
}
]
}
],
"package": {
"name": "bouncycastle",
"purl": "pkg:deb/debian/bouncycastle?arch=source&distro=bookworm",
"ecosystem": "Debian:12"
},
"versions": [
"1.72-2",
"1.77-1",
"1.80-1",
"1.80-2",
"1.80-3",
"1.86-1"
],
"database_specific": {
"source": "https://storage.googleapis.com/debian-osv/debian-cve-osv/DEBIAN-CVE-2026-71887.json"
},
"ecosystem_specific": {
"urgency": "not yet assigned"
}
},
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
}
]
}
],
"package": {
"name": "bouncycastle",
"purl": "pkg:deb/debian/bouncycastle?arch=source&distro=trixie",
"ecosystem": "Debian:13"
},
"versions": [
"1.80-3",
"1.86-1"
],
"database_specific": {
"source": "https://storage.googleapis.com/debian-osv/debian-cve-osv/DEBIAN-CVE-2026-71887.json"
},
"ecosystem_specific": {
"urgency": "not yet assigned"
}
},
{
"ranges": [
{
"type": "ECOSYSTEM",
"events": [
{
"introduced": "0"
},
{
"fixed": "1.86-1"
}
]
}
],
"package": {
"name": "bouncycastle",
"purl": "pkg:deb/debian/bouncycastle?arch=source&distro=forky",
"ecosystem": "Debian:14"
},
"versions": [
"1.80-3"
],
"database_specific": {
"source": "https://storage.googleapis.com/debian-osv/debian-cve-osv/DEBIAN-CVE-2026-71887.json"
},
"ecosystem_specific": {
"urgency": "not yet assigned"
}
}
],
"modified": "2026-10-07T09:47:40.065531604Z",
"provider": "osv",
"upstream": [
"CVE-2026-71887"
],
"references": [
"https://security-tracker.debian.org/tracker/CVE-2026-71887"
]
},
"related_cves": [
{
"value": "CVE-2026-71887",
"evidence": "/upstream"
}
],
"security_relevant": true,
"severity_evidence": "/severity/0/score"
},
"source_id": "core-osv",
"document_id": 94680,
"published_at": "2026-10-03T09:17:05.067+00:00"
}