Forge: X.509 basicConstraints bypass in verifyCertificateChain() via deprecated extension OIDs 2.5.29.10 and 2.5.29.13
Impact
The node-forge library, versions less than 1.4.1, has a vulnerability where it incorrectly validates X.509 certificates, allowing a certificate with a forged deprecated-OID extension to be accepted as a CA certificate. This requires an attacker to have a trusted CA issue a certificate with the attacker-supplied extension. The impact allows the holder of such a certificate to issue certificates for any name that node-forge accepts.
Summarized by @cf/meta/llama-3.3-70b-instruct-fp8-fast. Verify details against the original sources.Exploitation requires a CA trusted by the application to issue a certificate that contains the attacker-supplied deprecated-OID extension, typically a CA that copies extensions from certificate signing requests.
Affected packages
Start with the recorded fix for your release branch. Check your installed version and test compatibility before upgrading. Fixing this advisory does not rule out other vulnerabilities in the release.
| Affected range | Recorded fix |
|---|---|
| Earlier releases before 1.4.1Semantic versions | 1.4.1 |
Version evidence: OSV · GHSA-5x38-2vff-x55p
View original version evidence (0 explicit versions)
Affected products
Vendor version evidence. Product records are separate from automatic dependency matching.
digitalbazaar · GitHub_M
forge
1 range
digitalbazaar · GitHub_M
forge
Compare with this publisher’s ranges. This does not inspect your installation.
affected
< 1.4.1
Other versions: unknown
Original source description
Summary
node-forge parses certificate extensions with the deprecated OIDs 2.5.29.10 and 2.5.29.13 as basicConstraints, and forge.pki.verifyCertificateChain() used the first extension with that name. A certificate with a forged deprecated-OID extension (cA TRUE) before its genuine basicConstraints extension (cA FALSE) is accepted as a CA certificate, and the same technique can hide a pathLenConstraint. Fixed in node-forge 1.4.1.
Details
lib/oids.js maps the deprecated certificate extension OIDs 2.5.29.10 and 2.5.29.13 to the name basicConstraints, the same name as the RFC 5280 extension 2.5.29.19. certificateExtensionFromAsn1() in lib/x509.js decodes extensions by name, so these extensions are decoded into the same cA and pathLenConstraint fields. cert.getExtension() returns the first extension with a matching name, and pki.verifyCertificateChain() looked up basicConstraints by name.
As a result, a certificate that contains a 2.5.29.10 (or 2.5.29.13) extension with cA TRUE before its genuine basicConstraints extension with cA FALSE is accepted as a CA certificate. The same technique can hide a CA certificate's pathLenConstraint. A deprecated-OID extension on its own also satisfies the check added for GHSA-2328-f5f3-gj25 (CVE-2026-33896) that basicConstraints is present. RFC 5280 section 4.2.1.9 defines basicConstraints only as id-ce 19 (2.5.29.19), and the path validation checks in section 6.1.4 apply to that extension.
The fix makes chain verification look up basicConstraints by OID (cert.getExtension({id: '2.5.29.19'})). This covers both the cA and the pathLenConstraint checks. Certificate parsing, the OID table and cert.getExtension('basicConstraints') are unchanged.
Patches
Fixed in node-forge 1.4.1. Chain verification now uses only the basicConstraints extension with OID 2.5.29.19.
Workarounds
None in node-forge itself. Applications that pass an options.verify callback to pki.verifyCertificateChain() (or verify to forge.tls.createConnection()) can reject chains in which a non-leaf certificate has no 2.5.29.19 extension with cA TRUE, for example with cert.getExtension({id: '2.5.29.19'}). CA operators can avoid copying unrecognized extensions from certificate requests.
Credits
WorkOS Security Team· security@workos.com (@nickcollisson-workos)
Proof of concept
Have a trusted CA issue an end-entity certificate whose extensions are, in this order: a 2.5.29.10 (or 2.5.29.13) extension with the value of a basicConstraints cA TRUE (DER 30 03 01 01 FF), then the CA's own 2.5.29.19 basicConstraints with cA FALSE, and no keyUsage. For example, openssl x509 -req -copy_extensions copy with an extensions file that sets basicConstraints = CA:FALSE copies the extension from the CSR and produces this order. Use that certificate's key to sign a leaf certificate for any name.
On node-forge <= 1.4.0, forge.pki.verifyCertificateChain(caStore, [leaf, eeCert]) accepts the chain, and eeCert.getExtension('basicConstraints') returns the 2.5.29.10 extension with cA true. The same certificate without the deprecated-OID extension is rejected ("Certificate basicConstraints indicates the certificate is not a CA."). A certificate with only the deprecated-OID extension is also accepted.
The fix adds regression tests in tests/unit/x509.js and the reporter's PoC as tests/pocs/ghsa-5x38-2vff-x55p.js.
Impact
Applications that verify certificate chains with forge.pki.verifyCertificateChain(), including TLS peer certificate verification in forge.tls, are affected.
Exploitation requires a CA trusted by the application to issue a certificate that contains the attacker-supplied deprecated-OID extension, typically a CA that copies extensions from certificate signing requests. For example, openssl x509 -req -copy_extensions copy (or copyall) with an extensions file that sets basicConstraints = CA:FALSE and no keyUsage produces such a certificate. If the issuing CA adds a keyUsage extension without keyCertSign, node-forge rejects the chain.
The holder of such a certificate can then issue certificates for any name that pki.verifyCertificateChain() accepts. In forge's own TLS stack this allows impersonating servers (or clients, where client certificates are verified) and intercepting traffic.
Inside the record
Evidence available
Describes the evidence in this view, not whether the product is safe.
Original records
CVE-2026-119190View the latest unmodified CVE JSON from the official source. It may be newer than this imported page.
cve.new JSON →Underlying weaknesses
The source’s classification of what caused the vulnerability.
Contributing organizations · 2
Assigning organization
Additional data publisher
What changed
Follow changes- CVE · CVE-2026-119190
Observed 2026-10-29T21:08:14.390Z · upstream updated 2026-10-29T20:25:04.131Z
Prioritization updated
before
[]
after
[ { "source": "CISA-ADP", "type": "SSVC", "role": "CISA Coordinator", "timestamp": "2026-10-29T20:24:38.825329Z", "decisions": [ { "name": "Exploitation", "value": "poc" }, { "name": "Automatable", "value": "no" }, { "name": "Technical Impact", "value": "total" } ] } ]
Large field values are marked as truncated previews. Original source snapshots remain retained.
Showing up to 50 most recent observed changes.