Node.js aborts before JavaScript execution under sandbox-exec on macOS — LIBIGNITION termination code 2

I am investigating a startup failure when running Node.js under a restrictive sandbox-exec profile. I would appreciate guidance on diagnosing the failure and on a supported way to run a command-line process with restricted filesystem access and no network access.

I have not established whether this is caused by my profile, the operating system, or another interaction.

Environment
  • macOS 26.6.2, build 25G83
  • Apple silicon, ARM64, without Rosetta
  • Official Node.js 22.23.4 darwin-arm64 distribution; its archive SHA-256 matches the published checksum
  • Python 3.14 launching the process from Terminal
  • No sudo, application code, third-party JavaScript modules, credentials, or real user data

The Node version above identifies the downloaded distribution. I have not confirmed a successful node --version execution in this restricted environment.

Launch configuration

The invocation has this form:

/usr/bin/sandbox-exec -f <PROFILE> <NODE> -e <JS> <INPUT> <WORK>

Python uses subprocess.Popen, with:

  • Working directory set to <WORK>
  • start_new_session=True
  • Standard output and error captured through pipes
  • A 10-second execution deadline and a 6-second termination/cleanup allowance

Only these environment variables are supplied; the parent environment is not inherited:

PATH=<NODE_DIR>:/usr/bin:/bin
HOME=<WORK>
TMPDIR=<WORK>

NODE_OPTIONS and DYLD_* are not set.

The JavaScript starts with:

console.log("NODE_JS_ENTRY");

It then uses node:fs to read a synthetic input and write markers in the permitted work directory. The initial console marker is never observed.

Filesystem and network restrictions

The profile uses (deny default) and (deny network*). It permits process creation, execution of the specified Node binary, and sysctl-read.

File reads are allowed for the Node binary, synthetic input/work directories, /System/Library, /usr/lib, and the specific devices /dev/null, /dev/random, and /dev/urandom. Ancestor-directory metadata access is listed using individual literal paths. Writes are allowed only inside the work directory.

The Node binary and synthetic fixtures are in separate dedicated directories under the user's Documents directory.

This is a description of the profile, not a complete runnable reproduction. Paths are anonymized here.

I tested two additional permission variants:

A — ancestor metadata and existence checks:

(allow file-read-metadata file-test-existence
  (literal "/System/Volumes")
  (literal "/System/Volumes/Preboot"))

A+B — the above plus Cryptexes reads and executable mapping:

(allow file-read* file-map-executable file-test-existence
  (subpath "/System/Volumes/Preboot/Cryptexes"))

Neither variant resolved the startup failure. No general Mach/IPC permissions, broad /etc read access, localhost access, or system.sb import were added.

Observed results

The original profile and both variants terminated with SIGABRT, without the initial JavaScript marker.

For A and A+B:

  • Python reported child return code -6.
  • Standard output and error were both empty.
  • The parent sent no termination signal; these were not timeout terminations.
  • The direct child was reaped, and its process group was no longer present.

For two earlier executions using the original profile, I matched saved crash reports to the process and Node binary image. They showed:

Exception: EXC_CRASH / SIGABRT
Termination namespace: 0x23
Termination code: 2
Termination flags: 582

The stack included:

__abort_with_payload
abort_with_payload_wrapper_internal
abort_with_reason
ignition_halt
boot_boot
ignite
dyld4::CacheFinder::CacheFinder
dyld4::ProcessConfig::DyldCache::DyldCache
dyld4::ProcessConfig::ProcessConfig
dyld4::start
start

Apple's public XNU definitions identify namespace 35 as OS_REASON_LIBIGNITION. I have not established the meaning of code 2 for this OS build.

I have not inspected matching crash stacks for A or A+B, so I cannot claim they stopped at the same internal location.

Questions
  1. Is sandbox-exec a supported mechanism for this use case on this macOS version? If not, what supported approach can enforce both restricted filesystem access and no network access for a command-line process and its children?
  2. What diagnostic information would distinguish a missing sandbox permission from a loader/cache initialization problem?
  3. Does this termination signature suggest a documented diagnostic procedure or known issue?

My goal is to reach JavaScript execution while preserving the restrictions, rather than broadly allowing filesystem access or network communication. I can provide a sanitized profile and relevant diagnostic excerpts if needed.

Thank you.

Correction and update after checking the saved crash reports:

The original-profile runs were on macOS 26.6.2 (25G83), while the A and A+B runs were on macOS 26.7.2 (25G332). My initial post did not distinguish these environments correctly.

The saved reports for A and A+B have now been matched to the recorded execution times, process IDs, and Node image information. Both show SIGABRT, termination namespace 0x23, code 2, and the same 11-frame sequence of function names and offsets as the original-profile reports, including ignite, boot_boot, and ignition_halt.

The Node image UUID is unchanged, but the OS version and dyld image identifiers differ. These results therefore must not be treated as a controlled comparison in which only the sandbox profile changed.

The matching termination signatures do not establish an identical root cause. The specific reason for LIBIGNITION code 2 remains unknown. No additional executions or permission changes have been performed.

Answered by DTS Engineer in 913986022
Written by CLUCLU in 854443021

1- Is sandbox-exec a supported mechanism for this use case on this macOS version?

No.

The specific macOS version doesn’t matter.

See my responses on this thread for more background to this issue.

ps If you have LIBIGNITION crash report, please post it here, ideally in .ips format. See Posting a Crash Report for advice on how to do that.

IMPORTANT That won’t change my answer, but I’d like to get a copy of such a crash report because these crashes do come up from time-to-time (for example, here) and I want to learn how to recognise them better.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Written by CLUCLU in 854443021

1- Is sandbox-exec a supported mechanism for this use case on this macOS version?

No.

The specific macOS version doesn’t matter.

See my responses on this thread for more background to this issue.

ps If you have LIBIGNITION crash report, please post it here, ideally in .ips format. See Posting a Crash Report for advice on how to do that.

IMPORTANT That won’t change my answer, but I’d like to get a copy of such a crash report because these crashes do come up from time-to-time (for example, here) and I want to learn how to recognise them better.

Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"