Forge: Certificate signature verified with the issuer's RSA signature scheme
Published 10 Nov 2026 · Updated 10 Nov 2026
Is your project on an affected node-forge?
Affected package
- Affected
- <1.4.1
- Fixed in
- 1.4.1
npm install node-forge@1.4.1Details
Summary
When verifying a certificate, node-forge chose the RSA padding scheme (PKCS#1 v1.5 or RSASSA-PSS) and PSS parameters from the issuer certificate's own signature algorithm instead of the certificate being verified. A certificate labeled as signed with RSASSA-PSS could pass verifyCertificateChain() with a PKCS#1 v1.5 signature. Fixed in node-forge 1.4.1.
Details
certificate.verify(child) in lib/x509.js hashes the child's TBSCertificate with the digest of the child's signature algorithm, then calls _verifySignature() with the issuer certificate. _verifySignature() selected the padding scheme from that certificate's signatureOid and signatureParameters, so the child was verified with the issuer's own scheme rather than the one the child declares.
As a result, a child certificate whose signature algorithm says RSASSA-PSS was accepted with a PKCS#1 v1.5 signature when the issuer itself was signed with PKCS#1 v1.5. The outer signatureAlgorithm field of a certificate is not covered by the signature, so an existing PKCS#1 v1.5 (SHA-256) certificate can be relabeled as RSASSA-PSS and still pass verification. The signature itself must still be made with the issuer's private key over the certificate's contents; no certificate can be forged.
The same cause made correctly signed chains fail: a PKCS#1 v1.5 certificate issued by an RSASSA-PSS-signed certificate, or the reverse, was rejected.
The fix verifies with the child certificate's signature scheme and parameters and the issuer's public key.
Patches
Fixed in node-forge 1.4.1. Certificate signatures are verified with the scheme of the certificate's own signature algorithm.
Workarounds
Applications that make decisions based on a certificate's signature algorithm can verify the signature themselves with that algorithm's scheme and the issuer's public key.
References
- https://www.rfc-editor.org/rfc/rfc4055#section-3 (RSASSA-PSS signature algorithm in certificates)
- https://www.rfc-editor.org/rfc/rfc5280#section-4.1.1.2 (Certificate signatureAlgorithm)
- https://cwe.mitre.org/data/definitions/347.html (CWE-347: Improper Verification of Cryptographic Signature)
Severity
CVSS 3.1: CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:L/A:N (3.7, Low) CVSS 4.0 (informational): CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:L/VA:N/SC:N/SI:N/SA:N (6.3) CVSS 4.0 rates this Moderate because its integrity weighting is higher; the severity rating follows CVSS 3.1.
Credits
Reported by Brian Lee (@hibrian827, Georgia Tech SSLab, Team Atlanta), who also suggested the fix.
Proof of concept
Create a CA certificate signed with sha256WithRSAEncryption, and a leaf certificate whose signature algorithm fields (outer and in the TBSCertificate) are RSASSA-PSS with SHA-256/MGF1-SHA-256/salt 32, but sign the leaf's TBSCertificate with the CA key using PKCS#1 v1.5 (caKey.sign(sha256)).
On 1.4.0, forge.pki.verifyCertificateChain(forge.pki.createCaStore([ca]), [leaf]) returns true, although verifying the leaf's signature with RSASSA-PSS fails. On 1.4.1 it throws "Certificate signature is invalid.".
No private key is needed for the same result: take any certificate signed by the CA with sha256WithRSAEncryption and replace only its outer signatureAlgorithm (outside the signed TBSCertificate) with the RSASSA-PSS identifier above. On 1.4.0 it still verifies and reports signatureOid as RSASSA-PSS; on 1.4.1 it is rejected.
Regression tests are in tests/unit/x509.js ("signature scheme of the child certificate").
Impact
Applications that rely on a certificate's declared signature algorithm, for example a policy that only accepts RSASSA-PSS-signed certificates, can be given a certificate labeled RSASSA-PSS whose signature was verified as PKCS#1 v1.5. The certificate must still have been signed by the trusted issuer's key, so the identity it certifies cannot be forged. There is no confidentiality or availability impact.
Is GHSA-9wg5-mj3p-v49q in any of your client repos?
Checking one package by hand is fine. Checking it across forty client projects is not. NPMscan reads the lockfiles in every GitHub repo you pick, finds each project with an affected node-forge, and gives you the command that fixes it.
More advisories for node-forge
- LowCVE-2026-125335Forge: Ed25519 signature verification accepts small-order public keys · 10 Nov 2026
- MediumCVE-2026-125332Forge: TLS client crash on an unsupported ServerHello compression method · 10 Nov 2026
- MediumCVE-2026-125333Forge: ReDoS in forge.http response header and cookie trimming · 10 Nov 2026
- MediumCVE-2026-125334Forge: TLS client crash on a handshake record received without a session · 10 Nov 2026
- LowCVE-2026-118776Forge: Incomplete PKCS#7 padding validation in AES/DES CBC and ECB decryption · 10 Nov 2026
- MediumCVE-2026-119189Forge: X.509 pathLenConstraint not enforced by verifyCertificateChain() for CA certificates without keyUsage · 10 Nov 2026
References
Advisory data from OSV.dev (opens OSV.dev in a new tab), refreshed daily.