[GH-ISSUE #7377] [Bug] inspect-keyed-archive accepts an empty target and reads the working-directory bundle #4386

Closed
opened 2026-10-31 00:49:24 +00:00 by bsakaguchi · 0 comments
Owner

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

Before submitting

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

Area

CLI

Observed behavior

From inside a synthetic app bundle, inspect-keyed-archive "" Resources/Archive.plist --json exits 0 and returns successful inspect_keyed_archive Evidence for that bundle's archive. The response preserves parameters.input_path: "" while returning two archive objects, including resource-only-value. Explicit . also succeeds; the empty selection receives no validation error.

Reproduction

Use Node.js 24.22.1 and the source commit below. From a fresh checkout, install the locked dependencies with npm ci and build with npm run build:cached; the verifier rebuilt an already installed checkout. Run this shell block from the checkout root. It uses only synthetic files and isolates all product state below $WORK.

REA_ENTRY="$PWD/scripts/rea.mjs"
WORK="${WORK:-$(mktemp -d)}"
export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data"
export XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/temp"
mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$TMPDIR" "$WORK/Example.app/Resources"
printf '<plist><dict/></plist>' > "$WORK/Example.app/Info.plist"
cat > "$WORK/Example.app/Resources/Archive.plist" <<'PLIST'
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0"><dict><key>$archiver</key><string>NSKeyedArchiver</string><key>$version</key><integer>100000</integer><key>$objects</key><array><string>$null</string><string>resource-only-value</string></array><key>$top</key><dict><key>root</key><dict><key>UID</key><integer>1</integer></dict></dict></dict></plist>
PLIST
cd "$WORK/Example.app"
node "$REA_ENTRY" inspect-keyed-archive "" Resources/Archive.plist --json --filter-output 'parameters.input_path,normalized_result.total_objects'
printf 'empty exit=%s\n' "$?"
node "$REA_ENTRY" inspect-keyed-archive . Resources/Archive.plist --json --filter-output 'parameters.input_path,normalized_result.total_objects'
printf 'dot exit=%s\n' "$?"
node "$REA_ENTRY" inspect-byte-entropy "" --json
printf 'entropy exit=%s\n' "$?"

This exact reduced replay reproduced once. Before it, the same empty-target case succeeded twice on a fixture with an additional XML DOCTYPE: once with filtered output and once with complete Evidence. Both fixture runs included successful explicit-dot and rejected empty entropy controls.

Expected behavior

Reject the empty target before resolving or reading the working directory. docs/cli.md:42-45 promises that local inspection rejects empty paths before resolution and that an empty string never selects the working directory. src/cli/artifactCommands.ts:28-37 advertises this command for a plist archive or app bundle, so the promise applies. Preserve the successful explicit . control.

Impact and scope

P2: a script passing an empty target variable can obtain successful analysis of an unintended local bundle. A safe caller workaround is to reject empty target values before invocation. The observed scope is the built CLI's resource-only bundle route on macOS; no app was executed or changed. MCP, other platforms and other inspection commands are untested scope for this report. No security boundary was crossed.

REA version

Exact node scripts/rea.mjs --version output: 6.8.0. Built source commit: 0e17aab45196eb298e761f9ed0e846404e01eefa.

Runtime and platform

Node.js v24.22.1; macOS 27.0.1, Darwin 27.0.0, arm64. No Hopper, Ghidra, IDA, device or live service was used.

Target and artifact context

Synthetic root-layout .app directory containing an empty-dictionary Info.plist and an XML NSKeyedArchiver envelope with two objects. The resource-only route supports bundles without an executable declaration; no executable is required.

Interface

CLI

Earliest failure stage

Request parsing or validation

Relevant output or evidence

Observed output from the reduced replay:

{"normalized_result":{"total_objects":2},"parameters":{"input_path":""}}
empty exit=0
{"normalized_result":{"total_objects":2},"parameters":{"input_path":"."}}
dot exit=0

The entropy control exits 1 with code: "VALIDATION_ERROR" and a fieldErrors entry containing path: "path", code: "too_small", and missing: false. Complete keyed-archive output independently confirmed the working bundle's resource root and object 1's value resource-only-value; the result is not only an output-filter artifact.

Typed outcome or recovery expected

A nonzero input-validation result identifying path, before resource admission. A proposed restoration check is to replay the empty and explicit-dot commands: reject the former and retain the latter's two-object result.

Analysis or suspected cause

Source-derived: src/cli/artifactCommands.ts:32 accepts a bare string and forwards it unchanged. src/application/DirectAnalysis.ts:347-367,751-757 resolves and opens a directory for bundle-resource operations. src/filesystem/callerPath.ts:27-50 turns the empty relative path into the current directory; src/application/AppBundleExecutable.ts:117-140 then admits its resource root. The command does not apply a nonempty check before that resource admission.

Additional context

Closed #6757 reports the historical desktop-command equivalent; merged PR #2687 covered analyze and inspect-artifact. Open #7280 and PR #7284 concern decompile-all. Their command-specific fixes do not cover this independently reproduced keyed-archive route. No open duplicate was found in live open/closed issue and PR searches or the local all-issues snapshot.

Originally created by @coygeek on GitHub (Oct 27, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/7377 ## 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 CLI ## Observed behavior From inside a synthetic app bundle, `inspect-keyed-archive "" Resources/Archive.plist --json` exits 0 and returns successful `inspect_keyed_archive` Evidence for that bundle's archive. The response preserves `parameters.input_path: ""` while returning two archive objects, including `resource-only-value`. Explicit `.` also succeeds; the empty selection receives no validation error. ## Reproduction Use Node.js 24.22.1 and the source commit below. From a fresh checkout, install the locked dependencies with `npm ci` and build with `npm run build:cached`; the verifier rebuilt an already installed checkout. Run this shell block from the checkout root. It uses only synthetic files and isolates all product state below `$WORK`. ```sh REA_ENTRY="$PWD/scripts/rea.mjs" WORK="${WORK:-$(mktemp -d)}" export HOME="$WORK/home" XDG_CONFIG_HOME="$WORK/config" XDG_DATA_HOME="$WORK/data" export XDG_CACHE_HOME="$WORK/cache" XDG_STATE_HOME="$WORK/state" TMPDIR="$WORK/temp" mkdir -p "$HOME" "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME" "$XDG_STATE_HOME" "$TMPDIR" "$WORK/Example.app/Resources" printf '<plist><dict/></plist>' > "$WORK/Example.app/Info.plist" cat > "$WORK/Example.app/Resources/Archive.plist" <<'PLIST' <?xml version="1.0" encoding="UTF-8"?> <plist version="1.0"><dict><key>$archiver</key><string>NSKeyedArchiver</string><key>$version</key><integer>100000</integer><key>$objects</key><array><string>$null</string><string>resource-only-value</string></array><key>$top</key><dict><key>root</key><dict><key>UID</key><integer>1</integer></dict></dict></dict></plist> PLIST cd "$WORK/Example.app" node "$REA_ENTRY" inspect-keyed-archive "" Resources/Archive.plist --json --filter-output 'parameters.input_path,normalized_result.total_objects' printf 'empty exit=%s\n' "$?" node "$REA_ENTRY" inspect-keyed-archive . Resources/Archive.plist --json --filter-output 'parameters.input_path,normalized_result.total_objects' printf 'dot exit=%s\n' "$?" node "$REA_ENTRY" inspect-byte-entropy "" --json printf 'entropy exit=%s\n' "$?" ``` This exact reduced replay reproduced once. Before it, the same empty-target case succeeded twice on a fixture with an additional XML DOCTYPE: once with filtered output and once with complete Evidence. Both fixture runs included successful explicit-dot and rejected empty entropy controls. ## Expected behavior Reject the empty target before resolving or reading the working directory. `docs/cli.md:42-45` promises that local inspection rejects empty paths before resolution and that an empty string never selects the working directory. `src/cli/artifactCommands.ts:28-37` advertises this command for a plist archive or app bundle, so the promise applies. Preserve the successful explicit `.` control. ## Impact and scope P2: a script passing an empty target variable can obtain successful analysis of an unintended local bundle. A safe caller workaround is to reject empty target values before invocation. The observed scope is the built CLI's resource-only bundle route on macOS; no app was executed or changed. MCP, other platforms and other inspection commands are untested scope for this report. No security boundary was crossed. ## REA version Exact `node scripts/rea.mjs --version` output: `6.8.0`. Built source commit: `0e17aab45196eb298e761f9ed0e846404e01eefa`. ## Runtime and platform Node.js `v24.22.1`; macOS `27.0.1`, Darwin `27.0.0`, `arm64`. No Hopper, Ghidra, IDA, device or live service was used. ## Target and artifact context Synthetic root-layout `.app` directory containing an empty-dictionary Info.plist and an XML NSKeyedArchiver envelope with two objects. The resource-only route supports bundles without an executable declaration; no executable is required. ## Interface CLI ## Earliest failure stage Request parsing or validation ## Relevant output or evidence Observed output from the reduced replay: ```text {"normalized_result":{"total_objects":2},"parameters":{"input_path":""}} empty exit=0 {"normalized_result":{"total_objects":2},"parameters":{"input_path":"."}} dot exit=0 ``` The entropy control exits 1 with `code: "VALIDATION_ERROR"` and a `fieldErrors` entry containing `path: "path"`, `code: "too_small"`, and `missing: false`. Complete keyed-archive output independently confirmed the working bundle's resource root and object 1's value `resource-only-value`; the result is not only an output-filter artifact. ## Typed outcome or recovery expected A nonzero input-validation result identifying `path`, before resource admission. A proposed restoration check is to replay the empty and explicit-dot commands: reject the former and retain the latter's two-object result. ## Analysis or suspected cause Source-derived: `src/cli/artifactCommands.ts:32` accepts a bare string and forwards it unchanged. `src/application/DirectAnalysis.ts:347-367,751-757` resolves and opens a directory for bundle-resource operations. `src/filesystem/callerPath.ts:27-50` turns the empty relative path into the current directory; `src/application/AppBundleExecutable.ts:117-140` then admits its resource root. The command does not apply a nonempty check before that resource admission. ## Additional context Closed [#6757](https://github.com/morluto/rea/issues/6757) reports the historical desktop-command equivalent; merged [PR #2687](https://github.com/morluto/rea/pull/2687) covered `analyze` and `inspect-artifact`. Open [#7280](https://github.com/morluto/rea/issues/7280) and [PR #7284](https://github.com/morluto/rea/pull/7284) concern `decompile-all`. Their command-specific fixes do not cover this independently reproduced keyed-archive route. No open duplicate was found in live open/closed issue and PR searches or the local all-issues snapshot.
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#4386
No description provided.