[GH-ISSUE #1819] [Bug] inspect-artifact reports executable:false for every Windows host file, including real PE .exe images #614

Closed
opened 2026-10-15 18:26:39 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @JasonBuildAI on GitHub (Oct 11, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/1819

Observed behavior

On a Windows host, every occurrence built from host files reports executable: false, including genuine PE executables. The same occurrence simultaneously reports artifact_kind: executable and artifact_format: pe, so a single record contradicts itself.

Two host-file paths derive the fact from POSIX mode bits:

  • src/artifacts/DirectoryArtifactReader.ts:273 (artifactEntry)
  • src/artifacts/inventory/scanCanonical.ts:214 (root occurrence)
executable: (metadata.mode & 0o111) !== 0,

Windows has no POSIX execute bit. Node's fs.stat reports mode 0o666 for every file on NTFS, .exe included, so the bit test can never be true on a Windows host.

Reproduction

Windows 11 x64, Node 22.22.2, REA source revision ed084b3d (package version 6.4.0).

  1. Copy any real PE image to a scratch directory, e.g. whoami.exe.
  2. Run rea inspect-artifact whoami.exe (or MCP open_binary + inspect_artifact on the same file).
  3. Read the root occurrence.

Raw CLI output excerpt (node scripts/rea.mjs inspect-artifact .\whoami.exe):

sha256: 23240ef9f8b0a9a324110b1c2331de31dc1b0e08f5359cb707e51a939af56cd3
artifact_kind: executable
artifact_format: pe
executable: false

The mode read itself, on the same host:

$ node -e "const fs=require('fs');for(const p of ['a.exe','a.dat','a.txt']){console.log(p,(fs.statSync(p).mode & 0o777).toString(8))}"
a.exe 666
a.dat 666
a.txt 666

An executable script cannot be distinguished from data either: chmod on Windows only toggles the read-only flag, so mode & 0o111 is always 0.

Expected behavior

executable should state whether the file carries the host's executable marking. On POSIX hosts that is the execute permission bit (current behavior, unchanged). On Windows there is no such bit; the OS marks launchable files by extension (.exe, .com, .bat, .cmd), so whoami.exe should report executable: true, and the field should stop contradicting artifact_kind/artifact_format in the same occurrence.

Impact and scope

  • Affected: every Windows host user of inspect-artifact and of MCP inspect_artifact, plus compare_artifacts, which diffs this fact (src/domain/artifactComparison.ts:311) and so can never report a permission change for Windows-hosted inventories. Evidence consumers (agent clients included) receive a wrong fact that claims a PE executable is not executable.
  • Not affected: archive-derived facts (ZIP/ASAR/XY) keep their stored permission metadata; extraction is already documented as not reproducing permission bits.
  • Evidence integrity: a false executable: false is reported as observed rather than unknown, and it directly contradicts the byte-derived kind of the same occurrence.

REA version

6.4.0 (source revision ed084b3d)

Runtime and platform

Node 22.22.2; Windows 11 x64 (NTFS)

Target and artifact context

PE x64 image copied from C:\Windows\System32\whoami.exe; also reproducible for any .exe

Interface

CLI

Earliest failure stage

Artifact or evidence registration

Relevant output or evidence

The excerpt above. The same field is produced for the directory-aggregate root in scanCanonical.ts and for every directory entry in DirectoryArtifactReader.ts.

Typed outcome or recovery expected

Not applicable; the occurrence fact should be correct rather than typed as an error.

Analysis or suspected cause

Source-derived: both call sites test metadata.mode & 0o111. This is a derivation from the cited lines, not a runtime trace. On Windows, libuv fills stat.mode from the file attributes only (0666 for files, 0444 when read-only), so no host file can pass the test.

Additional context

A regression test can run on all platforms if the derivation is a pure function of (platform, path, mode): the Windows branch is then testable under Linux CI, and the real host case runs in the curated Windows lane (.github/workflows/ci.yml, windows-curated).

Originally created by @JasonBuildAI on GitHub (Oct 11, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/1819 ### Observed behavior On a Windows host, every occurrence built from host files reports `executable: false`, including genuine PE executables. The same occurrence simultaneously reports `artifact_kind: executable` and `artifact_format: pe`, so a single record contradicts itself. Two host-file paths derive the fact from POSIX mode bits: - `src/artifacts/DirectoryArtifactReader.ts:273` (`artifactEntry`) - `src/artifacts/inventory/scanCanonical.ts:214` (root occurrence) ```ts executable: (metadata.mode & 0o111) !== 0, ``` Windows has no POSIX execute bit. Node's `fs.stat` reports mode `0o666` for every file on NTFS, `.exe` included, so the bit test can never be true on a Windows host. ### Reproduction Windows 11 x64, Node 22.22.2, REA source revision `ed084b3d` (package version 6.4.0). 1. Copy any real PE image to a scratch directory, e.g. `whoami.exe`. 2. Run `rea inspect-artifact whoami.exe` (or MCP `open_binary` + `inspect_artifact` on the same file). 3. Read the root occurrence. Raw CLI output excerpt (`node scripts/rea.mjs inspect-artifact .\whoami.exe`): ```text sha256: 23240ef9f8b0a9a324110b1c2331de31dc1b0e08f5359cb707e51a939af56cd3 artifact_kind: executable artifact_format: pe executable: false ``` The mode read itself, on the same host: ```text $ node -e "const fs=require('fs');for(const p of ['a.exe','a.dat','a.txt']){console.log(p,(fs.statSync(p).mode & 0o777).toString(8))}" a.exe 666 a.dat 666 a.txt 666 ``` An executable script cannot be distinguished from data either: `chmod` on Windows only toggles the read-only flag, so `mode & 0o111` is always 0. ### Expected behavior `executable` should state whether the file carries the host's executable marking. On POSIX hosts that is the execute permission bit (current behavior, unchanged). On Windows there is no such bit; the OS marks launchable files by extension (`.exe`, `.com`, `.bat`, `.cmd`), so `whoami.exe` should report `executable: true`, and the field should stop contradicting `artifact_kind`/`artifact_format` in the same occurrence. ### Impact and scope - Affected: every Windows host user of `inspect-artifact` and of MCP `inspect_artifact`, plus `compare_artifacts`, which diffs this fact (`src/domain/artifactComparison.ts:311`) and so can never report a permission change for Windows-hosted inventories. Evidence consumers (agent clients included) receive a wrong fact that claims a PE executable is not executable. - Not affected: archive-derived facts (ZIP/ASAR/XY) keep their stored permission metadata; extraction is already documented as not reproducing permission bits. - Evidence integrity: a false `executable: false` is reported as observed rather than unknown, and it directly contradicts the byte-derived kind of the same occurrence. ### REA version 6.4.0 (source revision ed084b3d) ### Runtime and platform Node 22.22.2; Windows 11 x64 (NTFS) ### Target and artifact context PE x64 image copied from `C:\Windows\System32\whoami.exe`; also reproducible for any `.exe` ### Interface CLI ### Earliest failure stage Artifact or evidence registration ### Relevant output or evidence The excerpt above. The same field is produced for the directory-aggregate root in `scanCanonical.ts` and for every directory entry in `DirectoryArtifactReader.ts`. ### Typed outcome or recovery expected Not applicable; the occurrence fact should be correct rather than typed as an error. ### Analysis or suspected cause Source-derived: both call sites test `metadata.mode & 0o111`. This is a derivation from the cited lines, not a runtime trace. On Windows, libuv fills `stat.mode` from the file attributes only (0666 for files, 0444 when read-only), so no host file can pass the test. ### Additional context A regression test can run on all platforms if the derivation is a pure function of `(platform, path, mode)`: the Windows branch is then testable under Linux CI, and the real host case runs in the curated Windows lane (`.github/workflows/ci.yml`, `windows-curated`).
bsakaguchi 2026-10-15 18:26:39 +00:00
Author
Owner

@JasonBuildAI commented on GitHub (Oct 11, 2026):

AI disclosure: this report was drafted with AI assistance at my request, under my direction and review.

<!-- gh-comment-id:6109480306 --> @JasonBuildAI commented on GitHub (Oct 11, 2026): AI disclosure: this report was drafted with AI assistance at my request, under my direction and review.
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#614
No description provided.