GHSA-6qrw-m8cv-hcxf: Forge: RSA PKCS#1 v1.5 signature forgery via non-canonical DigestInfo encoding

Published Nov 10, 2026
·
Updated

Summary RSASSA-PKCS1-v15 signature verification (publicKey.verify() with the default scheme, also used by X.509 certificate and PKCS#7 verification) accepted non-canonical BER encodings of the DigestInfo, such as NULL parameters with content and non-minimal lengths. These leave attacker-controlled bytes inside an accepted DigestInfo, which allows signatures to be forged without the private key for RSA keys with a low public exponent (e=3). Fixed in node-forge 1.4.1.

Details In lib/rsa.js, key.verify() with the default RSASSA-PKCS1-V15 scheme removes the padding, parses the recovered DigestInfo with the lenient BER parser asn1.fromDer() and checks its structure with asn1.validate() against digestInfoValidator. Neither requires a canonical DER encoding, so verification accepted, among others: - NULL parameters with content bytes (e.g. 05 40 <64 bytes>) - non-NULL or constructed values in the parameters position - non-minimal (long form) and indefinite lengths - non-canonical OID encodings (padded subidentifiers, trailing bytes)

These leave attacker-controlled bytes inside an accepted DigestInfo. For RSA keys with a low public exponent (e=3) this allows signatures to be forged without the private key (BERserk / Bleichenbacher-style forgery, see CVE-2014-1568).

RFC 8017 section 8.2.2 verifies a signature by encoding the expected EMSA-PKCS1-v15 message and comparing it with the recovered one; section 9.2 defines the DigestInfo encoding.

The fix adds encodeDigestInfo(), which DER-encodes the expected DigestInfo from the digest algorithm OID and the digest (with and without NULL parameters). Verification now requires the recovered DigestInfo to match one of these encodings byte for byte. The same change fixes GHSA-2g46-22mc-6gwp (CVE-2026-85393).

Patches Fixed in node-forge 1.4.1. Verification now re-encodes the expected DigestInfo and requires a byte-for-byte match (RFC 8017 section 8.2.2).

Workarounds Do not use RSA keys with a low public exponent (e=3) for signature verification.

References - https://www.rfc-editor.org/rfc/rfc8017#section-8.2.2 - https://www.rfc-editor.org/rfc/rfc8017#section-9.2 - CVE-2026-85393 / GHSA-2g46-22mc-6gwp (related, same fix) - CVE-2026-33894 / https://github.com/digitalbazaar/forge/security/advisories/GHSA-ppp5-5v6c-4jwp - https://www.cve.org/CVERecord?id=CVE-2014-1568 (BERserk)

Severity CVSS 3.1: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N (7.5, High) CVSS 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) Both versions rate this High. The severity rating follows CVSS 3.1.

Credits Independently reported by Oren Yomtov (@orenyomtov, Fireblocks), Bronson Yen (Calif.io, in collaboration with Claude and Anthropic Research), Kamil Hałajda, @pzartech, @antonlissone and @Brechard.

Proof of concept DigestInfo encodings accepted before 1.4.1 (SHA-256; OID = 06 09 60 86 48 01 65 03 04 02 01, H = the 32-byte digest):

NULL parameters with content: 30 33 30 0F <OID> 05 02 BE EF 04 20 <H> non-minimal DigestInfo length: 30 81 31 30 0D <OID> 05 00 04 20 <H> (canonical form: 30 31 30 0D <OID> 05 00 04 20 <H>)

Long-form lengths are accepted the same way for the DigestAlgorithm, OID, NULL and digest fields. A signature whose EMSA-PKCS1-v15 block (00 01 FF..FF 00 || DigestInfo) contains such an encoding verified as valid: publicKey.verify(digest, signature) returned true. Content bytes in the NULL parameters (reports used e.g. 05 40 <64 bytes>) and similar slack give an attacker room to construct a forged signature for an e=3 key. With 1.4.1, verification throws "ASN.1 object does not contain a valid RSASSA-PKCS1-v15 DigestInfo value."

Regression tests: tests/unit/rsa.js, "canonical DigestInfo checks". They use an e=1 key, so the signature equals the encoded block, with one test per non-canonical shape (also indefinite length, constructed and non-NULL parameters, padded OID subidentifiers) and two tests that the canonical encodings with and without NULL parameters still verify. Included in the 1.4.1 release.

Impact Applications that verify RSASSA-PKCS1-v15 signatures with node-forge: publicKey.verify() with the default scheme, and X.509 certificate and PKCS#7 signature verification, which use it. If the verifying RSA public key has a low public exponent (e=3), an attacker can forge a signature that verifies as valid, without the private key. Only keys with a small public exponent such as e=3 are practically affected.

Affected Software

2 affected componentsFixes available
npm/node-forge<=1.4.0
1.4.1
npm/node-forge<1.4.1
1.4.1

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade npm/node-forge to a version that resolves this vulnerability.

    Fixed in 1.4.1
  2. Upgrade

    Upgrade node-forge to a version that resolves this vulnerability.

    Fixed in 1.4.1
  3. Compensating control

    Do not use RSA keys with a low public exponent (e=3) for signature verification.

Event History

Nov 10, 2026
Advisory Published
via GitHub·03:57 PM
Data Sourced
via GitHub·03:57 PM
DescriptionSeverityWeaknessAffected Software

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203