[GH-ISSUE #7555] [Bug] inspect-signature rejects valid thin arm64e Mach-O files #4496

Closed
opened 2026-10-31 00:50:17 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @coygeek on GitHub (Oct 27, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/7555

Before submitting

  • I searched the open and closed issues for a related report.
  • I removed credentials, tokens, private paths, and sensitive target data.

Area

Native analysis or decompilation

Observed behavior

node scripts/rea.mjs inspect-signature "$WORK/fixture-arm64e" --format json exits 1 with execution_failure for an Apple-signed thin arm64e executable extracted from the system /bin/ls. The native diagnostic says object file format unrecognized, invalid, or unsuitable, and REA returns no signature facts. The same behavior occurs for the extracted arm64e.x1 slice.

Both inputs pass codesign --verify. inspect-macho succeeds and identifies the exact thin subtype. Direct codesign display, requirement and entitlement queries succeed when selecting that subtype. Selecting arm64 instead produces the same object-format failure as REA.

Reproduction

  1. Use the already built baseline checkout below with Node.js 24.22.1 on PATH, on an arm64 Mac with Apple's command-line tools. Confirm lipo -archs /bin/ls includes arm64e. The tested host also lists arm64e.x1.
  2. From the checkout root, extract a disposable slice and compare native validation with the two public REA commands. These commands were executed through an isolated subprocess harness; the shell form below handles the expected failure without stopping before the controls.
WORK="$(mktemp -d -t rea-thin-signature)"
mkdir -p "$WORK/home" "$WORK/config" "$WORK/cache"   "$WORK/data" "$WORK/state" "$WORK/temp"
run_rea() {
  env -i PATH="$PATH" HOME="$WORK/home"     XDG_CONFIG_HOME="$WORK/config" XDG_CACHE_HOME="$WORK/cache"     XDG_DATA_HOME="$WORK/data" XDG_STATE_HOME="$WORK/state"     TMPDIR="$WORK/temp" node scripts/rea.mjs "$@"
}
lipo /bin/ls -thin arm64e -output "$WORK/fixture-arm64e"
codesign --verify --verbose=2 "$WORK/fixture-arm64e"
run_rea inspect-macho "$WORK/fixture-arm64e" --format json
if run_rea inspect-signature "$WORK/fixture-arm64e" --format json; then
  echo 'REA signature inspection succeeded'
else
  echo "REA signature inspection exited $?"
fi
codesign -d -a arm64e --verbose=4 "$WORK/fixture-arm64e"
if codesign -d -a arm64 --verbose=4 "$WORK/fixture-arm64e"; then
  echo 'Family-name control succeeded'
else
  echo "Family-name control exited $?"
fi
rm -rf "$WORK"
  1. REA signature inspection and the family-name control each exit 1. Native verification, exact-subtype display and Mach-O inspection exit 0. Replacing arm64e with arm64e.x1 in the fixture and exact-subtype commands gives the second tested case; leave the -a arm64 control unchanged.

The independent verification repeated REA signature inspection three times per subtype: 3/3 failures for arm64e and 3/3 for arm64e.x1. No fixture was executed.

Expected behavior

Return the selected thin executable's signing facts through the existing signature-inspection result. The tool contract promises the selected Mach-O architecture's identity, hashes, authorities, designated requirement, entitlements and hardened-runtime state. The CLI accepts a Mach-O path without excluding these subtypes. These files pass admission, native signature verification and another public Mach-O inspection command; an architecture-name mismatch should not prevent their signature inspection. Contract and implementation locators are listed under Evidence.

Impact and scope

P2: the two tested valid thin inputs deterministically receive no normalized signature result. The generic format diagnostic and doctor remediation do not identify the architecture mismatch. No input modification or data loss was observed.

A safe workaround was verified for both fixtures: run codesign -d -a <exact subtype> --verbose=4, codesign -d -a <exact subtype> -r- and codesign -d -a <exact subtype> --entitlements :- directly. All six commands exit 0, recovering the native facets outside REA's combined Evidence. The entitlement command also emits a deprecation warning for colon syntax.

Coverage is limited to these extracted system slices on the platform below. Other subtypes, compiled arm64e-only applications, Intel hosts, older macOS versions and MCP transport were not tested.

REA version

Exact node scripts/rea.mjs --version output:

6.8.0

Source baseline: 65f1c447344a423fa2785847dbcea1e9a9e2454a.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1, build 26A434; arm64. Native Apple lipo and codesign from the system command-line tools. No Hopper, Ghidra, GUI or process-table shim was involved.

Target and artifact context

Thin arm64e and arm64e.x1 Mach-O executable copies produced by lipo -thin from /bin/ls. Both identify as com.apple.ls; native verification reports each as valid on disk and satisfying its designated requirement. The system executable is never modified.

Interface

CLI

Earliest failure stage

Native analysis or reconstruction

Relevant output or evidence

Independently captured results, with generated paths represented by placeholders:

Input subtype                            arm64e         arm64e.x1
codesign --verify --verbose=2             exit 0         exit 0
codesign -d -a <exact subtype> --verbose=4 exit 0         exit 0
codesign -d -a arm64 --verbose=4           exit 1         exit 1
REA inspect-macho --format json           exit 0         exit 0
REA inspect-signature --format json       exit 1 (3/3)   exit 1 (3/3)

The successful Mach-O results contain selected_architecture: {"name":"arm64e","container_file_offset":0} and the equivalent arm64e.x1 selection. Their Evidence subjects use the broader architecture arm64.

All six signature failures contain these meaningful fields:

{
  "code": "execution_failure",
  "retryable": false,
  "details": {
    "provider_id": "native-macos",
    "operation": "inspect_signature",
    "diagnostics": {
      "tool": "codesign",
      "reason": "nonzero-exit",
      "exit_code": 1,
      "signal": null
    }
  }
}

Captured stderr is <private snapshot>: object file format unrecognized, invalid, or unsuitable. The error recommends rea doctor; no cleanup failure surrounds it. Exact-subtype display reports Identifier=com.apple.ls and Format=Mach-O thin (arm64e) or Format=Mach-O thin (arm64e.x1). Exact-subtype requirement queries return identifier "com.apple.ls" and anchor apple.

Source at the baseline:

  • Expected contract: src/contracts/native/nativeToolContracts.ts:116-120; public CLI registration and path argument: src/cli/utilityCommands.ts:193-215.
  • Failure-producing architecture: src/domain/binaryTarget.ts:150-155 and :713-724 map each thin input's CPU type to the arm64 family.
  • Provider reachability and guard: src/native/NativeMacOSProvider.ts:708-722 accepts executable Mach-O inputs and binds the snapshot. At :737-754, the provider takes target.architecture, translates only x86 to i386, and passes it to the first codesign display as -a. The display refusal returns at :764-769; later facets use the same spelling at :772 and :785.
  • Successful exact-subtype Mach-O selection uses the lipo inventory in src/native/NativeMachoInspection.ts:91-116.

Typed outcome or recovery expected

For each verified fixture, inspect-signature should exit 0 with the selected executable's signing facts and actual native-command provenance. Keep genuine unreadable-file, changed-snapshot and unrelated codesign failures typed as failures. These are restoration criteria; no repair was implemented or tested.

Analysis or suspected cause

Source-derived explanation, supported by native controls: admission stores the CPU family as arm64, and signature inspection reuses it as codesign's exact architecture selector. On these thin images, -a arm64 does not match the subtype; -a arm64e and -a arm64e.x1 respectively do. The failure occurs in the first display query before requirement, entitlement or universal-slice processing. The failing CLI result itself does not include successful command provenance, so the incorrect argument is established from the current source and matching direct-command behavior.

Additional context

Duplicate review included open and closed issues, issue comments, and open/closed/merged PRs. Related #4280, #1168 and #6799 concern FAT artifact inventory; #674 and #3389 concern inspect-macho; #5191 concerns labels and container vocabulary. Closed #684/#5697 concern mixed universal-signature failures, while #4293 and open #7390 concern universal result coverage. Their inputs and restoration checks differ from this thin-file first-query refusal. No historical known-good runtime or first-bad revision was established.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7555 ### Before submitting - [x] I searched the open and closed issues for a related report. - [x] I removed credentials, tokens, private paths, and sensitive target data. ### Area Native analysis or decompilation ### Observed behavior `node scripts/rea.mjs inspect-signature "$WORK/fixture-arm64e" --format json` exits 1 with `execution_failure` for an Apple-signed thin arm64e executable extracted from the system `/bin/ls`. The native diagnostic says `object file format unrecognized, invalid, or unsuitable`, and REA returns no signature facts. The same behavior occurs for the extracted arm64e.x1 slice. Both inputs pass `codesign --verify`. `inspect-macho` succeeds and identifies the exact thin subtype. Direct `codesign` display, requirement and entitlement queries succeed when selecting that subtype. Selecting `arm64` instead produces the same object-format failure as REA. ### Reproduction 1. Use the already built baseline checkout below with Node.js 24.22.1 on PATH, on an arm64 Mac with Apple's command-line tools. Confirm `lipo -archs /bin/ls` includes `arm64e`. The tested host also lists `arm64e.x1`. 2. From the checkout root, extract a disposable slice and compare native validation with the two public REA commands. These commands were executed through an isolated subprocess harness; the shell form below handles the expected failure without stopping before the controls. ```sh WORK="$(mktemp -d -t rea-thin-signature)" mkdir -p "$WORK/home" "$WORK/config" "$WORK/cache" "$WORK/data" "$WORK/state" "$WORK/temp" run_rea() { env -i PATH="$PATH" HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_CACHE_HOME="$WORK/cache" XDG_DATA_HOME="$WORK/data" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/temp" node scripts/rea.mjs "$@" } lipo /bin/ls -thin arm64e -output "$WORK/fixture-arm64e" codesign --verify --verbose=2 "$WORK/fixture-arm64e" run_rea inspect-macho "$WORK/fixture-arm64e" --format json if run_rea inspect-signature "$WORK/fixture-arm64e" --format json; then echo 'REA signature inspection succeeded' else echo "REA signature inspection exited $?" fi codesign -d -a arm64e --verbose=4 "$WORK/fixture-arm64e" if codesign -d -a arm64 --verbose=4 "$WORK/fixture-arm64e"; then echo 'Family-name control succeeded' else echo "Family-name control exited $?" fi rm -rf "$WORK" ``` 3. REA signature inspection and the family-name control each exit 1. Native verification, exact-subtype display and Mach-O inspection exit 0. Replacing `arm64e` with `arm64e.x1` in the fixture and exact-subtype commands gives the second tested case; leave the `-a arm64` control unchanged. The independent verification repeated REA signature inspection three times per subtype: 3/3 failures for arm64e and 3/3 for arm64e.x1. No fixture was executed. ### Expected behavior Return the selected thin executable's signing facts through the existing signature-inspection result. The tool contract promises the selected Mach-O architecture's identity, hashes, authorities, designated requirement, entitlements and hardened-runtime state. The CLI accepts a Mach-O path without excluding these subtypes. These files pass admission, native signature verification and another public Mach-O inspection command; an architecture-name mismatch should not prevent their signature inspection. Contract and implementation locators are listed under Evidence. ### Impact and scope P2: the two tested valid thin inputs deterministically receive no normalized signature result. The generic format diagnostic and doctor remediation do not identify the architecture mismatch. No input modification or data loss was observed. A safe workaround was verified for both fixtures: run `codesign -d -a <exact subtype> --verbose=4`, `codesign -d -a <exact subtype> -r-` and `codesign -d -a <exact subtype> --entitlements :-` directly. All six commands exit 0, recovering the native facets outside REA's combined Evidence. The entitlement command also emits a deprecation warning for colon syntax. Coverage is limited to these extracted system slices on the platform below. Other subtypes, compiled arm64e-only applications, Intel hosts, older macOS versions and MCP transport were not tested. ### REA version Exact `node scripts/rea.mjs --version` output: ```text 6.8.0 ``` Source baseline: `65f1c447344a423fa2785847dbcea1e9a9e2454a`. ### Runtime and platform Node.js v24.22.1; macOS 27.0.1, build 26A434; arm64. Native Apple lipo and codesign from the system command-line tools. No Hopper, Ghidra, GUI or process-table shim was involved. ### Target and artifact context Thin arm64e and arm64e.x1 Mach-O executable copies produced by `lipo -thin` from `/bin/ls`. Both identify as `com.apple.ls`; native verification reports each as valid on disk and satisfying its designated requirement. The system executable is never modified. ### Interface CLI ### Earliest failure stage Native analysis or reconstruction ### Relevant output or evidence Independently captured results, with generated paths represented by placeholders: ```text Input subtype arm64e arm64e.x1 codesign --verify --verbose=2 exit 0 exit 0 codesign -d -a <exact subtype> --verbose=4 exit 0 exit 0 codesign -d -a arm64 --verbose=4 exit 1 exit 1 REA inspect-macho --format json exit 0 exit 0 REA inspect-signature --format json exit 1 (3/3) exit 1 (3/3) ``` The successful Mach-O results contain `selected_architecture: {"name":"arm64e","container_file_offset":0}` and the equivalent `arm64e.x1` selection. Their Evidence subjects use the broader architecture `arm64`. All six signature failures contain these meaningful fields: ```json { "code": "execution_failure", "retryable": false, "details": { "provider_id": "native-macos", "operation": "inspect_signature", "diagnostics": { "tool": "codesign", "reason": "nonzero-exit", "exit_code": 1, "signal": null } } } ``` Captured stderr is `<private snapshot>: object file format unrecognized, invalid, or unsuitable`. The error recommends `rea doctor`; no cleanup failure surrounds it. Exact-subtype display reports `Identifier=com.apple.ls` and `Format=Mach-O thin (arm64e)` or `Format=Mach-O thin (arm64e.x1)`. Exact-subtype requirement queries return `identifier "com.apple.ls" and anchor apple`. Source at the baseline: - Expected contract: `src/contracts/native/nativeToolContracts.ts:116-120`; public CLI registration and path argument: `src/cli/utilityCommands.ts:193-215`. - Failure-producing architecture: `src/domain/binaryTarget.ts:150-155` and `:713-724` map each thin input's CPU type to the `arm64` family. - Provider reachability and guard: `src/native/NativeMacOSProvider.ts:708-722` accepts executable Mach-O inputs and binds the snapshot. At `:737-754`, the provider takes `target.architecture`, translates only x86 to i386, and passes it to the first codesign display as `-a`. The display refusal returns at `:764-769`; later facets use the same spelling at `:772` and `:785`. - Successful exact-subtype Mach-O selection uses the lipo inventory in `src/native/NativeMachoInspection.ts:91-116`. ### Typed outcome or recovery expected For each verified fixture, `inspect-signature` should exit 0 with the selected executable's signing facts and actual native-command provenance. Keep genuine unreadable-file, changed-snapshot and unrelated codesign failures typed as failures. These are restoration criteria; no repair was implemented or tested. ### Analysis or suspected cause Source-derived explanation, supported by native controls: admission stores the CPU family as `arm64`, and signature inspection reuses it as codesign's exact architecture selector. On these thin images, `-a arm64` does not match the subtype; `-a arm64e` and `-a arm64e.x1` respectively do. The failure occurs in the first display query before requirement, entitlement or universal-slice processing. The failing CLI result itself does not include successful command provenance, so the incorrect argument is established from the current source and matching direct-command behavior. ### Additional context Duplicate review included open and closed issues, issue comments, and open/closed/merged PRs. Related #4280, #1168 and #6799 concern FAT artifact inventory; #674 and #3389 concern inspect-macho; #5191 concerns labels and container vocabulary. Closed #684/#5697 concern mixed universal-signature failures, while #4293 and open #7390 concern universal result coverage. Their inputs and restoration checks differ from this thin-file first-query refusal. No historical known-good runtime or first-bad revision was established.
Author
Owner

@sathariels commented on GitHub (Oct 27, 2026):

I'd like to take this one. Plan: make the signature inspector accept thin arm64e Mach-O files (CPU subtype handling, including the pointer-auth ABI bits), with a regression test using a thin arm64e fixture. PR coming soon.

<!-- gh-comment-id:6455011402 --> @sathariels commented on GitHub (Oct 27, 2026): I'd like to take this one. Plan: make the signature inspector accept thin arm64e Mach-O files (CPU subtype handling, including the pointer-auth ABI bits), with a regression test using a thin arm64e fixture. PR coming soon.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#4496
No description provided.