Vulnerability details

7.5/10
CVSS 3.1
GHSA-jc66-7q78-782g
in_triage Published 2026-10-30 Updated 2026-10-30
Vulnerability Data from Dependency-Track
Description
### Summary forge.pkcs12.pkcs12FromAsn1() accepts a PKCS#12 MAC iteration count of zero (or less) from the input, and the PKCS#12 key derivation function then returns a constant key that does not depend on the password or salt. An attacker who does not know the password can modify a PKCS#12/PFX file and compute a MAC that verifies with any password; PKCS#12 PBE-encrypted private keys prepared the same way decrypt with any password. Fixed in node-forge 1.4.1. ### Details `p12.pkcs12FromAsn1()` in `lib/pkcs12.js` reads the MAC iteration count (`MacData.iterations`) from the input and passes it to the PKCS#12 key derivation function `pki.pbe.generatePkcs12Key()` in `lib/pbe.js` (also exposed as `forge.pkcs12.generateKey()`) without checking that it is at least 1. The key derivation function (RFC 7292 Appendix B.2) runs its hash loop `iter` times. With an iteration count of 0 (or an empty or negative INTEGER), no hashing is done and the function returns the PKCS#12 diversifier ID byte repeated, for example `0x03` repeated 20 times for an HMAC-SHA1 MAC key. The result does not depend on the password or the salt, so anyone can compute a valid MAC over arbitrary PFX contents. The same key derivation function is used by `pki.pbe.getCipherForPKCS12PBE()` for the PKCS#12 password-based encryption schemes `pbeWithSHAAnd3-KeyTripleDES-CBC` and `pbewithSHAAnd40BitRC2-CBC`, whose `pkcs-12PbeParams` iteration count is also read from the input. With an iteration count of 0 or less, the encryption key and IV are constants (`0x01` and `0x02` repeated). This is reached from shrouded key bags and encrypted SafeContents in `pkcs12FromAsn1()`, and from `forge.pki.decryptPrivateKeyInfo()` (for example for `ENCRYPTED PRIVATE KEY` PEM input). RFC 7292 defines `MacData` with `iterations INTEGER DEFAULT 1`; an iteration count only makes sense as 1 or more (RFC 8018 uses `INTEGER (1..MAX)` for the same concept). PBES2 (PBKDF2) encrypted content is not affected. The fix rejects iteration counts less than 1 when verifying a PKCS#12 MAC in `pkcs12FromAsn1()` ("PKCS#12 MAC iteration count must be >= 1.") and at the entry of `pki.pbe.generatePkcs12Key()` ("PKCS#12 key derivation iteration count must be >= 1."), which covers the MAC, both PKCS#12 PBE schemes and direct `forge.pkcs12.generateKey()` callers. ### Patches Fixed in node-forge 1.4.1. Iteration counts less than 1 are now rejected when verifying a PKCS#12 MAC and in the PKCS#12 key derivation function. ### Workarounds Before calling `forge.pkcs12.pkcs12FromAsn1()`, reject inputs whose `MacData.iterations` is present and less than 1. For encrypted private keys using the PKCS#12 PBE schemes, there is no simple workaround other than checking the `pkcs-12PbeParams` iteration count before decryption, or upgrading. ### Credits Reported by Thai, Calif.io in collaboration with Claude and Anthropic Research. ### Proof of concept Take any PKCS#12/PFX file, replace its AuthenticatedSafe with attacker-chosen content (for example the attacker's certificate and an unencrypted private key), set `MacData.iterations` to 0 (DER `02 01 00`), and compute the HMAC-SHA1 over the new content with the key `0x03` repeated 20 times. On node-forge <= 1.4.0, `forge.pkcs12.pkcs12FromAsn1(asn1, password)` reports successful MAC verification for whatever password the application supplies and returns the attacker's certificate and key. An empty or negative iteration count behaves the same way. Likewise, a shrouded key bag or `ENCRYPTED PRIVATE KEY` using `pbeWithSHAAnd3-KeyTripleDES-CBC` with iteration count 0 decrypts with any password. The constant key is visible directly: ```js var salt = new forge.util.ByteBuffer('anysalt'); forge.pkcs12.generateKey('any password', salt, 3, 0, 20).toHex(); // <= 1.4.0: '0303030303030303030303030303030303030303' // 1.4.1: throws "PKCS#12 key derivation iteration count must be >= 1." ``` The fix adds regression tests in `tests/unit/pkcs12.js` and the reporter's PoC in `tests/pocs/`. ### Impact Applications that import PKCS#12/PFX files or PKCS#8 encrypted private keys from untrusted sources with `forge.pkcs12.pkcs12FromAsn1()` or `forge.pki.decryptPrivateKeyInfo()`, and rely on the password-based MAC or on successful decryption to establish that the file was produced by someone who knows the password. The default API and call pattern are affected; no password, oracle or user interaction is needed, only one offline HMAC. An attacker can supply a PKCS#12 file with certificates and private keys of their choice (for example, replaced certificates or an unencrypted private key) that node-forge reports as verified under the application's password. The attacker does not learn the password or the original private key. PBES2 (PBKDF2) encrypted content is not affected.
Analysis Read only

CVE is a trademark and the CVE logo is a registered trademark of The MITRE Corporation. CVE data may be incomplete, delayed, or inaccurate. This website and all information provided are offered on an “as is” basis without warranties of any kind. This site is not affiliated with, endorsed by, or sponsored by the CVE Program or The MITRE Corporation.

This site uses data from the National Vulnerability Database (NVD), obtained through Dependency-Track, but is not endorsed or certified by the NVD or the National Institute of Standards and Technology (NIST). NVD data may be incomplete, delayed, or inaccurate.

CVSS (Common Vulnerability Scoring System) is owned and managed by FIRST.Org, Inc. and used by permission. The links on CVSS vectors open the FIRST CVSS calculators (CVSS 3.0, 3.1 and 4.0), or the NVD calculator for CVSS 2.0. This site is not affiliated with, endorsed by, or sponsored by FIRST.

GitHub is a trademark of GitHub, Inc. GHSA identifiers and advisory data come from the GitHub Advisory Database, licensed under CC-BY 4.0. GHSA data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by GitHub, Inc.

Source of the EUVD data: European Vulnerability Database (EUVD), © European Union Agency for Cybersecurity (ENISA), reused with acknowledgement of the source as provided by the ENISA legal notice and IPR policy. Changes: CVEManager does not display the EUVD records as such; it uses their aliases to link the CVE and GHSA identifiers designating the same vulnerability. EUVD data may be incomplete, delayed, or inaccurate. This site is not affiliated with, endorsed by, or sponsored by ENISA or the European Union.