{"id":"GHSA-h46v-rmh6-fq4f","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 \u003c 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 \u003c- int \u003c- subCA \u003c- 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// \u003c= 1.4.0: true (pathLenConstraint=0 ignored)\n// 1.4.1: throws \"Certificate basicConstraints pathLenConstraint violated.\"\n```\n\nThe same chain is rejected on \u003c= 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.","aliases":["CVE-2026-119189"],"modified":"2026-11-10T16:15:05.046196341Z","published":"2026-11-10T15:57:43Z","database_specific":{"nvd_published_at":"2026-10-29T20:17:29Z","cwe_ids":["CWE-295"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-11-10T15:57:43Z"},"references":[{"type":"WEB","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":"WEB","url":"https://github.com/digitalbazaar/forge/commit/696db92348623e88cc63c35f0a89ede481d55ad0"},{"type":"PACKAGE","url":"https://github.com/digitalbazaar/forge"},{"type":"WEB","url":"https://github.com/digitalbazaar/forge/releases/tag/v1.4.1"}],"affected":[{"package":{"name":"node-forge","ecosystem":"npm","purl":"pkg:npm/node-forge"},"ranges":[{"type":"SEMVER","events":[{"introduced":"0"},{"fixed":"1.4.1"}]}],"database_specific":{"last_known_affected_version_range":"\u003c= 1.4.0","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-h46v-rmh6-fq4f/GHSA-h46v-rmh6-fq4f.json"}}],"schema_version":"1.9.2","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:H/A:N"}]}