GHSA-5x38-2vff-x55p

    Dashboard / Vulnerabilities / GHSA-5x38-2vff-x55p

    GHSA-5x38-2vff-x55p

    Published: 30 Oct 2026Last Modified: 30 Oct 2026

    Summary: Forge: X.509 basicConstraints bypass in verifyCertificateChain() via deprecated extension OIDs 2.5.29.10 and 2.5.29.13

    Details: ### 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· [[email protected]](mailto:[email protected]) (@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.

    Affected packages

    Package

    Name: node-forge

    Purl: pkg:npm/node-forge

    Affected ranges

    Type: SEMVER

    Events:

    Introduced- 0
    Fixed -1.4.1

    Affected versions

    Common Vulnerability Scoring System

    Attack Vector
    Network
    Adjacent
    Local
    Physical
    Privileges Required
    None
    Low
    High
    User Interaction
    None
    Required
    Scope
    Unchanged
    Changed
    Confidentiality
    None
    Low
    High
    Integrity
    None
    Low
    High
    Availability
    None
    Low
    High