[GH-ISSUE #3871] [Bug] IDA attached universal analysis accepts a different slice than its Evidence architecture #1491

Closed
opened 2026-10-16 21:06:08 +00:00 by bsakaguchi · 0 comments
Owner

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

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

When open_binary opens a universal Mach-O through the IDA provider in an attached profile, REA selects the host architecture, admits the attached database using only the whole-input SHA-256, path, and image base, and labels the returned assembly with the host-selected architecture. Because both identity checks pass on the shared whole-file hash and nothing compares the loaded processor or selected slice, an attached database of a different slice of the same universal file yields assembly for that other architecture attributed to the host-selected one. This is a source-only finding; no IDA process was used.

In both attached profiles the attached database is admitted on the shared whole-file digest, path, and image base alone, and the returned assembly, pseudocode, and other observations are labeled with the host-selected architecture. When the attached database holds a different slice of the same universal input, x86_64 results are attributed to arm64, and the headless thinning safeguard that would extract the selected slice is never reached.

Reproduction

Source-only proof chain for open_binary with provider_id: "ida" on a universal Mach-O containing both x86_64 and arm64, followed by procedure_assembly for a function present in an attached database, where the attached database is of the x86_64 slice while the REA host is arm64 (legacy attached and native attached profiles):

  1. On an arm64 host, src/application/BinaryTargetResolver.ts:80-82 selects the host architecture and src/domain/binaryTarget.ts:147-159 records architecture: "arm64" with the arm64 byte range, while src/application/BinaryTargetResolver.ts:213-220 retains the universal file path and its whole-file SHA-256.
  2. An IDA database of the x86_64 slice of that same original input records an original-input SHA-256 equal to the universal file's SHA-256, satisfying the attached identity contract; this is the input condition, not an executed IDA run.
  3. src/ida/IdaProvider.ts:107-144 admits the universal target without rejecting multislice inputs or requiring proof of the loaded slice, and lines 174-188 pass the same target to IdaSessionClient, whose health runs at src/application/binary/BinarySession.ts:319-321.
  4. src/ida/IdaSessionClient.ts:547-603 allocates and thins an input only when mode === "headless", so attached mode reaches ready state without the thinning safeguard.
  5. src/ida/IdaSessionClient.ts:620-636 compares only the recorded SHA-256, path, and image base; the stable identity tuple and src/ida/IdaProtocolValues.ts:31-39 require no processor or slice identity, so any upstream processor metadata is never consumed.
  6. src/ida/IdaSessionClient.ts:294-337 runs the operation between those metadata checks, the stable metadata satisfies the post-check at lines 669-676, and src/ida/IdaOperationRunner.ts:637-638 returns the attached database's function assembly, which here is x86_64.
  7. The successful execution has no alternative subject, so src/application/binary/BinarySessionExecution.ts:118-147 binds the host-selected arm64 target, and src/server/registerOfficialTools.ts:80-98 with src/domain/evidence.ts:387-405 writes arm64 into the Evidence subject and semantic identity, attributing x86_64 assembly to arm64 with no unknown-slice outcome.

Expected behavior

The architecture attributed to analysis must match the architecture actually analyzed, or the adapter must leave the identity unresolved and fail closed. src/ida/IdaWorkspace.ts:59-62 states that the upstream engine must analyze the admitted architecture; docs/ida-provider.md:42 requires opening the original input and describes attached identity validation; docs/ida-provider.md:58 applies recorded-input and database identity checks to native attached mode; AGENTS.md:19-21 requires preserving identity and keeping unresolved identity unknown.

Impact and scope

Attached analysis of universal Mach-O inputs can attribute assembly, pseudocode, and other observations to a different CPU architecture than the one analyzed; the admission gap is established from source, but it is bounded to attached multislice targets and its frequency in real GUI sessions is unmeasured.

Workaround: available. Using the documented headless profile, whose selected-slice extraction is present at src/ida/IdaWorkspace.ts:64-100, or ensuring the attached GUI uses the same architecture as the REA host avoids the ambiguity; these follow from source and workflow contracts and were not run against IDA.

Reporter's impact estimate: P2 (provisional).

REA version

6.5.0, built from source at main commit 034342ba28 (latest npm release is 6.5.0)

Runtime and platform

Node.js v26.10.0; macOS 27.0.1 arm64; This finding is established from source at the tested build. Runtime reproduction was not run.

Target and artifact context

Universal Mach-O (x86_64 + arm64); attached IDA database; Evidence v2 subject

Interface

MCP

Earliest failure stage

Setup or provider admission

Relevant output or evidence

  • Expected source: src/ida/IdaWorkspace.ts:59-62 requires the upstream engine to analyze the admitted architecture, and docs/ida-provider.md:42 and docs/ida-provider.md:58 require opening the original input and applying recorded-input and database identity checks; AGENTS.md:19-21 requires keeping unresolved identity unknown.
  • Failure source: the static chain above, in particular src/ida/IdaSessionClient.ts:547-603 thinning only in headless mode, src/ida/IdaSessionClient.ts:620-636 and src/ida/IdaProtocolValues.ts:31-39 comparing no processor or slice identity, and src/application/binary/BinarySessionExecution.ts:118-147 binding the host-selected architecture to the result.
  • Evidence provenance: static
  • Local verification: static-proof
  • Reproduction completeness: complete

Typed outcome or recovery expected

procedure_assembly should have been labeled with the architecture actually analyzed, or the open should have failed closed with an unresolved-slice outcome, instead of attributing x86_64 assembly to an arm64 Evidence subject.

Restoration check:

Failing observable: an attached database of the x86_64 slice of a universal input returns x86_64 procedure_assembly whose Evidence subject architecture is arm64. Passing observable: on the same input the provider either returns results labeled x86_64 to match the analyzed slice or fails closed with an unresolved-slice outcome, so no cross-architecture attribution occurs. Control: the documented headless profile, whose selected-slice extraction lives at src/ida/IdaWorkspace.ts:64-100, resolves the slice explicitly and is not subject to this ambiguity.

Analysis or suspected cause

Attached mode admits the database on whole-file SHA-256, path, and image base only (src/ida/IdaSessionClient.ts:620-636, src/ida/IdaProtocolValues.ts:31-39), the headless thinning that would select the slice runs only when mode === headless (src/ida/IdaSessionClient.ts:547-603), and the subjectless execution is bound to the host-selected architecture (src/application/binary/BinarySessionExecution.ts:118-147) written to Evidence at src/domain/evidence.ts:387-405. The host architecture is chosen at src/application/BinaryTargetResolver.ts:80-82.

Additional context

Closed #2139 reports the same architecture-misattribution class in headless mode; this is the remaining attached-profile case rather than a claim that the headless fix regressed. Closed #2285 and closed #2548 concern bytes extending beyond a selected headless slice and are different. No open duplicate was found.

This report came from AI-assisted source review with local reproduction where stated above; the evidence labels distinguish observed runs from source-only reasoning.

Originally created by @coygeek on GitHub (Oct 15, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/3871 ### 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 When `open_binary` opens a universal Mach-O through the IDA provider in an attached profile, REA selects the host architecture, admits the attached database using only the whole-input SHA-256, path, and image base, and labels the returned assembly with the host-selected architecture. Because both identity checks pass on the shared whole-file hash and nothing compares the loaded processor or selected slice, an attached database of a different slice of the same universal file yields assembly for that other architecture attributed to the host-selected one. This is a source-only finding; no IDA process was used. In both attached profiles the attached database is admitted on the shared whole-file digest, path, and image base alone, and the returned assembly, pseudocode, and other observations are labeled with the host-selected architecture. When the attached database holds a different slice of the same universal input, x86_64 results are attributed to arm64, and the headless thinning safeguard that would extract the selected slice is never reached. ### Reproduction Source-only proof chain for `open_binary` with `provider_id: "ida"` on a universal Mach-O containing both x86_64 and arm64, followed by `procedure_assembly` for a function present in an attached database, where the attached database is of the x86_64 slice while the REA host is arm64 (legacy attached and native attached profiles): 1. On an arm64 host, src/application/BinaryTargetResolver.ts:80-82 selects the host architecture and src/domain/binaryTarget.ts:147-159 records `architecture: "arm64"` with the arm64 byte range, while src/application/BinaryTargetResolver.ts:213-220 retains the universal file path and its whole-file SHA-256. 2. An IDA database of the x86_64 slice of that same original input records an original-input SHA-256 equal to the universal file's SHA-256, satisfying the attached identity contract; this is the input condition, not an executed IDA run. 3. src/ida/IdaProvider.ts:107-144 admits the universal target without rejecting multislice inputs or requiring proof of the loaded slice, and lines 174-188 pass the same target to `IdaSessionClient`, whose health runs at src/application/binary/BinarySession.ts:319-321. 4. src/ida/IdaSessionClient.ts:547-603 allocates and thins an input only when `mode === "headless"`, so attached mode reaches ready state without the thinning safeguard. 5. src/ida/IdaSessionClient.ts:620-636 compares only the recorded SHA-256, path, and image base; the stable identity tuple and src/ida/IdaProtocolValues.ts:31-39 require no processor or slice identity, so any upstream processor metadata is never consumed. 6. src/ida/IdaSessionClient.ts:294-337 runs the operation between those metadata checks, the stable metadata satisfies the post-check at lines 669-676, and src/ida/IdaOperationRunner.ts:637-638 returns the attached database's function assembly, which here is x86_64. 7. The successful execution has no alternative subject, so src/application/binary/BinarySessionExecution.ts:118-147 binds the host-selected arm64 target, and src/server/registerOfficialTools.ts:80-98 with src/domain/evidence.ts:387-405 writes arm64 into the Evidence subject and semantic identity, attributing x86_64 assembly to arm64 with no unknown-slice outcome. ### Expected behavior The architecture attributed to analysis must match the architecture actually analyzed, or the adapter must leave the identity unresolved and fail closed. src/ida/IdaWorkspace.ts:59-62 states that the upstream engine must analyze the admitted architecture; docs/ida-provider.md:42 requires opening the original input and describes attached identity validation; docs/ida-provider.md:58 applies recorded-input and database identity checks to native attached mode; AGENTS.md:19-21 requires preserving identity and keeping unresolved identity unknown. ### Impact and scope Attached analysis of universal Mach-O inputs can attribute assembly, pseudocode, and other observations to a different CPU architecture than the one analyzed; the admission gap is established from source, but it is bounded to attached multislice targets and its frequency in real GUI sessions is unmeasured. Workaround: available. Using the documented headless profile, whose selected-slice extraction is present at src/ida/IdaWorkspace.ts:64-100, or ensuring the attached GUI uses the same architecture as the REA host avoids the ambiguity; these follow from source and workflow contracts and were not run against IDA. Reporter's impact estimate: P2 (provisional). ### REA version 6.5.0, built from source at main commit 034342ba28c8e56c3746be92b78aa7299afa02bd (latest npm release is 6.5.0) ### Runtime and platform Node.js v26.10.0; macOS 27.0.1 arm64; This finding is established from source at the tested build. Runtime reproduction was not run. ### Target and artifact context Universal Mach-O (x86_64 + arm64); attached IDA database; Evidence v2 subject ### Interface MCP ### Earliest failure stage Setup or provider admission ### Relevant output or evidence - Expected source: src/ida/IdaWorkspace.ts:59-62 requires the upstream engine to analyze the admitted architecture, and docs/ida-provider.md:42 and docs/ida-provider.md:58 require opening the original input and applying recorded-input and database identity checks; AGENTS.md:19-21 requires keeping unresolved identity unknown. - Failure source: the static chain above, in particular src/ida/IdaSessionClient.ts:547-603 thinning only in headless mode, src/ida/IdaSessionClient.ts:620-636 and src/ida/IdaProtocolValues.ts:31-39 comparing no processor or slice identity, and src/application/binary/BinarySessionExecution.ts:118-147 binding the host-selected architecture to the result. - Evidence provenance: static - Local verification: static-proof - Reproduction completeness: complete ### Typed outcome or recovery expected procedure_assembly should have been labeled with the architecture actually analyzed, or the open should have failed closed with an unresolved-slice outcome, instead of attributing x86_64 assembly to an arm64 Evidence subject. Restoration check: Failing observable: an attached database of the x86_64 slice of a universal input returns x86_64 `procedure_assembly` whose Evidence subject architecture is arm64. Passing observable: on the same input the provider either returns results labeled x86_64 to match the analyzed slice or fails closed with an unresolved-slice outcome, so no cross-architecture attribution occurs. Control: the documented headless profile, whose selected-slice extraction lives at src/ida/IdaWorkspace.ts:64-100, resolves the slice explicitly and is not subject to this ambiguity. ### Analysis or suspected cause Attached mode admits the database on whole-file SHA-256, path, and image base only (src/ida/IdaSessionClient.ts:620-636, src/ida/IdaProtocolValues.ts:31-39), the headless thinning that would select the slice runs only when mode === headless (src/ida/IdaSessionClient.ts:547-603), and the subjectless execution is bound to the host-selected architecture (src/application/binary/BinarySessionExecution.ts:118-147) written to Evidence at src/domain/evidence.ts:387-405. The host architecture is chosen at src/application/BinaryTargetResolver.ts:80-82. ### Additional context Closed #2139 reports the same architecture-misattribution class in headless mode; this is the remaining attached-profile case rather than a claim that the headless fix regressed. Closed #2285 and closed #2548 concern bytes extending beyond a selected headless slice and are different. No open duplicate was found. This report came from AI-assisted source review with local reproduction where stated above; the evidence labels distinguish observed runs from source-only reasoning.
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#1491
No description provided.