Skip to content

RangeError: Maximum call stack size exceeded in analyzeNode on deeply nested miniscript #12

Description

@Nuhiat-Arefin

Summary

compileMiniscript() throws RangeError: Maximum call stack size exceeded on a deeply nested but well-formed miniscript expression.

In local testing, parsing succeeds first; the overflow happens later in the analysis pass, specifically in analyzeNode, which appears to recurse through the AST without a depth bound.

Verified on @bitcoinerlab/miniscript v2.0.0 under Node v24.

Reproduction

const { compileMiniscript } = require('@bitcoinerlab/miniscript');

let ms = 'older(1)';
for (let i = 0; i < 1600; i++) {
  ms = `and_v(v:older(1),${ms})`;
}
ms = 'j:' + ms;

compileMiniscript(ms);

Observed behavior

The call throws:

RangeError: Maximum call stack size exceeded
    at analyzeNode (.../dist/compiler/analyze.js)
    at analyzeNode (...)
    ...

I verified this locally with n = 1600 and n = 3000. The input is deeply nested and well-formed, and parsing succeeds before the failure in analysis.

Why this seems to happen

The failure appears to come from recursive descent in analyzeNode over wrappers and child nodes without a nesting limit.

From local source review, the relevant logic is in src/compiler/analyze.ts around the main analyzeNode implementation and its recursive calls for wrappers and binary fragments.

Impact

This is an availability / robustness issue in the public compileMiniscript() API.

If an application compiles attacker-controlled or otherwise untrusted miniscript input, a deeply nested expression can trigger an unexpected raw RangeError instead of a normal validation error.

Expected behavior

A deeply nested miniscript should be rejected gracefully with a normal compile/validation error instead of overflowing the JavaScript call stack.

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