NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
📦
📦 npm
Not in CISA KEV
HIGH severity

Forge: ASN.1 resource exhaustion via BIT STRING decoding in asn1.fromDerGHSA-rhr8-3pm8-cq29

HIGHFix: digitalbazaar/forge@24035c1

GHSA-rhr8-3pm8-cq29 is a high-severity (CVSS 7.5) Uncontrolled Resource Consumption vulnerability in node-forge. A fix is available for node-forge — see the affected versions and patch details below.

Also known asCVE-2026-119191
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 10, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.

Exploitation and automatability from CISA’s SSVC triage for GHSA-rhr8-3pm8-cq29.

EPSS Exploitation Probability

via FIRST.org ↗
0.4%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs37th percentile — riskier than 37% of all scored CVEsHighest risk
0.00%0.31%0.62%0.93%0.4%0.4%Nov 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

How urgent is this, really

Where this sits among everything scored

Real-World Exposure

1 pkg affected

How broadly this vulnerability is actually deployed: weekly install volume shows current usage, and reverse-dependency count shows how many other packages break if it stays unpatched.

4Kother npm packages depend on this — each one inherits the vulnerability until it's patched upstream
node-forgenpm
54.5Mdownloads / week

Description

Summary

asn1.fromDer() decodes the contents of BIT STRINGs as ASN.1 by default. That decode ignored the maxDepth recursion limit (an incomplete fix of CVE-2025-66031) and also decoded nested BIT STRINGs, keeping a full copy of the decoded contents at each level, so small crafted DER or PEM inputs (certificates, keys, PKCS structures) use excessive CPU time and memory and can abort the Node.js process. Fixed in node-forge 1.4.1.

Details

asn1.fromDer() attempts by default to decode the contents of primitive BIT STRINGs as ASN.1 (decodeBitStrings, default true). Two flaws in that decode in lib/asn1.js allow resource exhaustion:

  1. _fromDer() started the BIT STRING decode with a new options object, {strict: true, decodeBitStrings: true}, that did not include maxDepth. Inside that decode the depth check compared against undefined and never triggered, so the recursion limit added for CVE-2025-66031 (GHSA-554w-wpv2-vw27) was not enforced for anything below a decoded BIT STRING. Both the global asn1.maxDepth (default 256) and the per-call maxDepth option were ignored there. Errors in this speculative decode, including stack overflows, are caught and the contents kept as raw bytes, so deep nesting is parsed instead of rejected. This is an incomplete fix of CVE-2025-66031.
  2. BIT STRINGs nested inside decoded BIT STRING contents were decoded as well, and asn1.create() gives each decoded BIT STRING a deep copy of its decoded contents (obj.original, used by toDer() to detect changes). Memory use therefore grows quadratically with the nesting depth, even within the default depth limit.

No specification is violated; the parser lacks a resource limit.

The fix passes maxDepth to the BIT STRING decode, and decodes BIT STRING contents with decodeBitStrings: false, so only one level of BIT STRING contents is decoded. Contents that would exceed the limit, and BIT STRINGs inside decoded BIT STRING contents, are kept as undecoded BIT STRING values; toDer() writes their original bytes. Common structures such as SubjectPublicKeyInfo only use one level. Code that relied on nested decoding can decode the inner value explicitly with asn1.fromDer().

Patches

Fixed in node-forge 1.4.1. The maxDepth limit now applies to ASN.1 decoded from BIT STRING contents, and only one level of BIT STRING contents is decoded.

Workarounds

Code that calls forge.asn1.fromDer() directly and does not need encapsulated BIT STRING contents decoded can pass {decodeBitStrings: false}. This changes the parsed structure. The higher-level PKI, PKCS and TLS APIs do not expose this option and rely on the decoded form. For those, the only remedy is upgrading.

References

Severity

CVSS 3.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (7.5, High) CVSS 4.0 (informational): CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N (8.7) Both versions rate this High. The severity rating follows CVSS 3.1.

Credits

Reported by Ethan Kim (cremit.io), Youngjoon Kim (@acorn421) and Brian Lee (@hibrian827) of Georgia Tech SSLab, @arpitjain099, and Mike Read.

Proof of concept

Input shape: n nested primitive BIT STRINGs (03 <len> 00 <inner>) around a NULL. For example:

var asn1 = forge.asn1;
var obj = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.NULL, false, '');
for(var i = 0; i < 2000; ++i) {
  obj = asn1.create(asn1.Class.UNIVERSAL, asn1.Type.BITSTRING, false, [obj]);
}
var der = asn1.toDer(obj).getBytes(); // 9,886 bytes
asn1.fromDer(der, {maxDepth: 10});

On 1.4.0 (Node.js 24) this parses all 2,000 levels despite maxDepth: 10, taking about 0.5-1 s and 600 MB. One SEQUENCE holding 20 such chains (about 198 KB) aborts a process with the default heap with "FATAL ERROR: JavaScript heap out of memory", which the application cannot catch. Within the depth limit, 80 chains of 254 levels (92 KB) still use about 0.8 GB. The same inputs wrapped as PEM reach pki.publicKeyFromPem() and pki.certificateFromPem() (a 20 KB certificate PEM used 1.3 GB before being rejected). On 1.4.1 these inputs parse in a few milliseconds and about 55-65 MB.

Regression tests in tests/unit/asn1.js: "should limit depth in decoded BIT STRINGs (default)", "should limit depth in decoded BIT STRINGs (maxDepth)", "should only decode one level of BIT STRINGs" and "should not decode BIT STRINGs in many BIT STRINGs".

Impact

A remote, unauthenticated attacker can supply a small DER or PEM structure with nested BIT STRINGs to any API that parses with asn1.fromDer() using default options. This includes pki.certificateFromPem(), pki.publicKeyFromPem(), the PKCS#7, PKCS#8 and PKCS#12 loaders, and server certificates received by forge's TLS client. Parsing such input consumes excessive CPU time and memory before the structure is rejected. On Node.js 24 a 10 KB input used about 600 MB and a 25 KB input about 1.4 GB. Inputs of about 25 KB abort a process limited to a 512 MB heap, and about 200 KB abort a process with the default heap, with a fatal out-of-memory error that the application cannot catch. Inputs that stay within the depth limit still reach about 0.8 GB at 92 KB and 1.8 GB at 231 KB. The result is denial of service. There is no confidentiality or integrity impact.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
📦npmnode-forgeall versions1.4.1npm install node-forge@1.4.1

Affected Products

1 product · 1 configurations
Application
forgedigitalbazaar
< 1.4.1
range

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for node-forge, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update node-forge to 1.4.1 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-rhr8-3pm8-cq29 is resolved across your whole dependency graph.

  3. Workarounds

    Stop feeding it untrusted input: reject or quarantine files and payloads from unverified sources until you can upgrade, restrict accepted formats to the ones you actually need, and run the parsing or decoding step in a least-privileged sandbox or short-lived worker so a crash or corrupted read cannot reach the rest of the process.

Fixing This On Your OS

If you run this on a Linux distribution, patch through your package manager against the distro's own security advisory below — it tracks the exact backported fix for your release, which can ship on a different timeline (and sometimes a different severity) than the upstream project.

Red HatImportant
Workaround published by Red Hat
--- CME Mitigation Guidance (2026-11-06) --- Disclaimer: The following mitigation solutions are provided as a courtesy, pending the application of an official patch. This content was generated utilizing AI tools in conjunction with data from https://cmetaxonomy.org. Customers are advised to independently evaluate and test these temporary mitigations within their own infrastructure. The highest-value action is to enforce recursion depth limits and disable nested BIT STRING decoding during ASN.1 parsing in node-forge: upgrade to node-forge 1.4.1 (or the corresponding fixed Red Hat builds), which propagate maxDepth into recursive subOptions and set decodeBitStrings to false so only one level…
Source: Red Hat security advisory for GHSA-rhr8-3pm8-cq29 (CC BY 4.0)

Frequently Asked Questions

### Summary `asn1.fromDer()` decodes the contents of BIT STRINGs as ASN.1 by default. That decode ignored the `maxDepth` recursion limit (an incomplete fix of CVE-2025-66031) and also decoded nested BIT STRINGs, keeping a full copy of the decoded contents at each level, so small crafted DER or PEM inputs (certificates, keys, PKCS structures) use excessive CPU time and memory and can abort the Node.js process. Fixed in node-forge 1.4.1. ### Details `asn1.fromDer()` attempts by default to decode the contents of primitive BIT STRINGs as ASN.1 (`decodeBitStrings`, default `true`). Two flaws in th
O3 Security · Impact-Aware SCA

Is GHSA-rhr8-3pm8-cq29 in your dependencies?

Find it across npm, including transitive dependencies.

Forge: ASN.1 resource exhaustion via BIT STRING…