{"id":"CVE-2026-119189","aliases":["GHSA-h46v-rmh6-fq4f"],"url":"https://o3.security/vulnerability/CVE-2026-119189","summary":"Forge: X.509 pathLenConstraint not enforced by verifyCertificateChain() for CA certificates without keyUsage","details":"### Summary\n`forge.pki.verifyCertificateChain()` enforces the `pathLenConstraint` of a CA certificate's `basicConstraints` extension only when that certificate also has a `keyUsage` extension. For a CA certificate with a `pathLenConstraint` and no `keyUsage`, chains with more intermediate CA certificates below it than the constraint allows are accepted. Fixed in node-forge 1.4.1.\n\n### Details\nIn `pki.verifyCertificateChain()` (`lib/x509.js`), the path length check for a CA certificate was guarded by `keyUsageExt !== null && 'pathLenConstraint' in bcExt`. The `keyUsage` test was originally a proxy for \"a basicConstraints extension exists\". Since node-forge 1.4.0 (GHSA-2328-f5f3-gj25), basicConstraints is required for every certificate that reaches this check, so the only remaining effect of the guard is to skip `pathLenConstraint` enforcement for CA certificates without `keyUsage`.\n\nRFC 5280 permits CA certificates without `keyUsage`, and path length processing in section 6.1.4 (l)-(m) does not depend on `keyUsage`; section 4.2.1.9 defines `pathLenConstraint` as part of basicConstraints only. For example, with a trusted root, an intermediate CA with `pathLenConstraint=0` and no `keyUsage`, a sub-CA issued by that intermediate, and a leaf issued by the sub-CA, node-forge accepts the chain. It correctly rejects the same chain when the intermediate has `keyUsage`.\n\nThe fix checks `pathLenConstraint` whenever the basicConstraints extension is present, regardless of `keyUsage` (based on PR #1142).\n\n#### Patches\nFixed in node-forge 1.4.1. `pathLenConstraint` is now enforced for CA certificates without a `keyUsage` extension.\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 CA certificate at `depth` d has `basicConstraints.pathLenConstraint < d - 1`. Re-issuing constrained CA certificates with a `keyUsage` extension that includes `keyCertSign` also restores enforcement.\n\n#### References\n- RFC 5280, sections 4.2.1.9 and 6.1.4: https://www.rfc-editor.org/rfc/rfc5280#section-6.1.4\n- Related: GHSA-2328-f5f3-gj25 / CVE-2026-33896 (basicConstraints bypass, fixed in 1.4.0)\n- https://github.com/digitalbazaar/forge/pull/1142\n\n#### Severity\nCVSS 3.1: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N (5.9, Moderate)\nCVSS 4.0 (informational): 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 (8.2)\nCVSS 4.0 weights the attack preconditions differently and scores this higher; the severity rating follows CVSS 3.1.\n\n#### Credits\n@offset, @eddieran, also reported independently by Zion Boggan (@zionboggan) and @EchoSkorJjj.\n\n### Proof of concept\nBuild the chain root <- int <- subCA <- leaf, where `int` has basicConstraints `cA=true, pathLenConstraint=0` and no `keyUsage`, `subCA` is a CA certificate issued by `int`, and `leaf` is issued by `subCA`:\n\n```js\nvar caStore = forge.pki.createCaStore([root]);\nforge.pki.verifyCertificateChain(caStore, [leaf, subCA, int]);\n// <= 1.4.0: true (pathLenConstraint=0 ignored)\n// 1.4.1: throws \"Certificate basicConstraints pathLenConstraint violated.\"\n```\n\nThe same chain is rejected on <= 1.4.0 when `int` also has a `keyUsage` extension with `keyCertSign`. The fix adds regression tests in `tests/unit/x509.js` and the reporter's PoC as `tests/pocs/ghsa-h46v-rmh6-fq4f.js`.\n\n### Impact\nApplications that verify certificate chains with `forge.pki.verifyCertificateChain()`, including TLS peer certificate verification in `forge.tls`, are affected when a CA they trust (directly or through a chain) has a `pathLenConstraint` and no `keyUsage` extension.\n\nExploitation requires such a path-length-constrained CA certificate that chains to a root the application trusts. The attacker must either hold that CA's private key or obtain a CA certificate from it. That CA can then create subordinate CAs, and certificates issued by those subordinate CAs are accepted by `pki.verifyCertificateChain()`. Public web PKI CA certificates normally include `keyUsage`. Private PKIs whose CA certificates were created without `keyUsage` are most likely to be affected.","published":"2026-10-29T19:23:25.238Z","modified":"2026-11-05T02:30:33.256711781Z","cvss":{"score":5.9,"severity":"MEDIUM","vector":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N"},"epss":null,"cisaKev":null,"exploitsKnown":null,"affectedPackages":[{"ecosystem":"npm","name":"node-forge","fixedVersion":"1.4.1"}],"fix":{"url":"https://github.com/digitalbazaar/forge/commit/696db92348623e88cc63c35f0a89ede481d55ad0","label":"digitalbazaar/forge@696db92"},"references":[{"type":"WEB","url":"https://github.com/digitalbazaar/forge/releases/tag/v1.4.1"},{"type":"ADVISORY","url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/119xxx/CVE-2026-119189.json"},{"type":"ADVISORY","url":"https://github.com/digitalbazaar/forge/security/advisories/GHSA-h46v-rmh6-fq4f"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2026-119189"},{"type":"FIX","url":"https://github.com/digitalbazaar/forge/commit/696db92348623e88cc63c35f0a89ede481d55ad0"},{"type":"PACKAGE","url":"https://github.com/digitalbazaar/forge"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-11-05T02:30:33.256711781Z"}}