{"id":"CVE-2026-119190","aliases":["GHSA-5x38-2vff-x55p"],"title":"Forge: X.509 basicConstraints bypass in verifyCertificateChain() via deprecated extension OIDs 2.5.29.10 and 2.5.29.13","titleSource":"GitHub_M","descriptionSource":"OSV","declaredSeverity":"HIGH","description":"### Summary\nnode-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.\n\n### Details\n`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.\n\nAs 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.\n\nThe 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.\n\n#### Patches\nFixed in node-forge 1.4.1. Chain verification now uses only the `basicConstraints` extension with OID `2.5.29.19`.\n\n#### Workarounds\nNone 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.\n\n#### Credits\n\nWorkOS Security Team· [security@workos.com](mailto:security@workos.com) (@nickcollisson-workos)\n\n### Proof of concept\nHave 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.\n\nOn 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.\n\nThe fix adds regression tests in `tests/unit/x509.js` and the reporter's PoC as `tests/pocs/ghsa-5x38-2vff-x55p.js`.\n\n### Impact\nApplications that verify certificate chains with `forge.pki.verifyCertificateChain()`, including TLS peer certificate verification in `forge.tls`, are affected.\n\nExploitation 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.\n\nThe 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.","severity":"high","score":7.4,"published":"2026-10-29T19:25:09.677Z","modified":"2026-10-30T23:15:08.080Z","withdrawn":false,"knownExploited":false,"affected":[{"ecosystem":"npm","name":"node-forge","sources":[{"name":"OSV · GHSA-5x38-2vff-x55p","url":"https://osv.dev/vulnerability/GHSA-5x38-2vff-x55p"}],"ranges":[{"events":[{"introduced":"0"},{"fixed":"1.4.1"}],"type":"SEMVER"}],"versions":[],"fixed":["1.4.1"]}],"sourceAffected":[],"references":["https://github.com/digitalbazaar/forge/security/advisories/GHSA-5x38-2vff-x55p","https://github.com/digitalbazaar/forge/commit/58c06bc251856b409c30ecb35a93f5f6c9bbc84a","https://github.com/digitalbazaar/forge/releases/tag/v1.4.1","https://nvd.nist.gov/vuln/detail/CVE-2026-119190","https://github.com/digitalbazaar/forge"],"sources":[{"name":"CVE","id":"CVE-2026-119190","modified":"2026-10-29T20:25:04.131Z","url":"https://www.cve.org/CVERecord?id=CVE-2026-119190"},{"name":"OSV","id":"GHSA-5x38-2vff-x55p","modified":"2026-10-30T23:15:08.080586742Z","url":"https://osv.dev/vulnerability/GHSA-5x38-2vff-x55p"}],"assessments":[{"source":"GitHub_M","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","score":7.4},{"source":"OSV","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:N","score":7.4}],"cve":{"records":[{"id":"CVE-2026-119190","source":"GitHub_M","state":"PUBLISHED","reasons":[],"replacements":[],"disputed":false,"unsupportedWhenAssigned":false,"reserved":"2026-10-29T16:04:48.728Z","published":"2026-10-29T19:25:09.677Z","modified":"2026-10-29T20:25:04.131Z"}],"publishers":[{"name":"GitHub_M","role":"CNA","organizationId":"a0819718-46f1-4df5-94e2-005712e83aaa","modified":"2026-10-29T19:25:09.677Z"},{"name":"CISA-ADP","role":"ADP","organizationId":"134c704f-9b21-4f2e-91b3-4a467353bcc0","modified":"2026-10-29T20:25:04.131Z"}],"references":[{"url":"https://github.com/digitalbazaar/forge/security/advisories/GHSA-5x38-2vff-x55p","tags":["x_refsource_CONFIRM"],"source":"GitHub_M"},{"url":"https://github.com/digitalbazaar/forge/commit/58c06bc251856b409c30ecb35a93f5f6c9bbc84a","tags":["x_refsource_MISC"],"source":"GitHub_M"},{"url":"https://github.com/digitalbazaar/forge/releases/tag/v1.4.1","tags":["x_refsource_MISC"],"source":"GitHub_M"},{"url":"https://github.com/digitalbazaar/forge/security/advisories/GHSA-5x38-2vff-x55p","tags":["exploit"],"source":"CISA-ADP"}],"weaknesses":[{"id":"CWE-295","description":"CWE-295: Improper Certificate Validation","source":"GitHub_M"},{"id":"CWE-436","description":"CWE-436: Interpretation Conflict","source":"GitHub_M"}],"applicability":[],"prioritization":[{"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"}]}]},"products":[{"vendor":"digitalbazaar","name":"forge","platforms":[],"versions":[{"version":"< 1.4.1","status":"affected"}],"cpes":[],"source":"GitHub_M","url":"https://www.cve.org/CVERecord?id=CVE-2026-119190"}],"remediation":[],"observedAt":"2026-10-30T23:32:04.784Z","kev":{"status":"not-listed","checkedAt":"2026-10-31T00:50:33.640Z"},"coverage":[{"source":"NVD","status":"no-result","checkedAt":"2026-10-29T19:50:35.170Z","attemptedAt":"2026-10-29T19:50:35.170Z"},{"source":"GHSA","status":"no-result","checkedAt":"2026-10-29T19:50:35.424Z","attemptedAt":"2026-10-29T19:50:35.424Z"},{"source":"EUVD","status":"refresh-failed","attemptedAt":"2026-10-29T19:50:34.963Z"},{"source":"EPSS","status":"no-result","checkedAt":"2026-10-29T19:50:35.452Z","attemptedAt":"2026-10-29T19:50:35.452Z"}],"evidence":[],"aiSummary":{"text":"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.","model":"@cf/meta/llama-3.3-70b-instruct-fp8-fast","generatedAt":"2026-10-31T00:01:42.396Z","sources":[{"name":"CVE","url":"https://www.cve.org/CVERecord?id=CVE-2026-119190"},{"name":"OSV","url":"https://osv.dev/vulnerability/GHSA-5x38-2vff-x55p"}]}}