[GH-ISSUE #4896] [Bug] Direct launcher ownership ignores symlink traversal before parent segments #3039

Closed
opened 2026-10-31 00:35:16 +00:00 by bsakaguchi · 1 comment
Owner

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

Before submitting

  • Searched related reports and PRs; #4895 covers unresolved aliases and #4847 stable version-manager launchers.
  • No credentials, private target paths, or sensitive data included.

Area

Setup, packaging, or upgrade

Observed behavior

Executed owned temporary fixtures on Node24.18.0/macOS arm64 while auditing the identity owner based on 01cdbbdc5. A direct executable path containing a symlink followed by .. runs the foreign fixture, but the classifier returns owned because it applies lexical path.resolve before inspecting the filesystem.

The Node-script form is a separate control: Node itself normalizes its script argument and runs the current fixture, so its owned classification is correct. Native executable coordinates and Node script arguments must retain their different resolution semantics.

Reproduction

Create root/entry.mjs printing current; root/other/entry.mjs is an executable shell fixture printing foreign; and root/link -> root/other/child. Let candidate = root/link/../entry.mjs.

  • execFileSync(candidate) executes the foreign shell fixture; the classifier for [candidate, "mcp"] returns owned, expected foreign.
  • execFileSync(process.execPath, [candidate]) executes the current Node fixture; [process.execPath, candidate, "mcp"] is correctly owned.
  • Kernel-backed reads observe different files. realpathSync.native reports different paths; legacy realpathSync reports equal paths on the tested Node build. Merely removing the initial path.resolve while retaining the legacy resolver is insufficient.

Temporary files were removed after execution. No external program or real agent configuration was changed.

Expected behavior

Use filesystem resolution for native executable coordinates. Model Node's script-argument selection separately, preserve configured values, and grant ownership only from the applicable interpretation. Failed identity lookup remains unknown (#4895).

Impact and scope

Observed: the canonical ownership classifier grants a false positive for the direct executable. Source-derived: uninstall and maintenance use this positive decision to select registrations, so an unrelated registration can be admitted for mutation. No destructive public workflow has been run at report creation; a controlled public uninstall regression is proposed. Real-world frequency and native Windows/Linux behavior are NOT_ENOUGH_INFO.

REA version

6.5.0; normalizing identity rule present at 01cdbbdc55; observed in the working-tree build based on that revision.

Runtime and platform

Node24.18.0, macOS arm64; own shell/Node fixtures only.

Target and artifact context

Owned launcher fixture files/symlinks; no reverse-engineering target.

Interface

Package or setup

Earliest failure stage

Setup or provider admission

Relevant output or evidence

Direct executable: runs foreign fixture, classification owned. Node script argument: runs current fixture, classification owned. readFileSync(candidate) and readFileSync(current) return different bytes. Owning normalization.

Typed outcome or recovery expected

Direct path foreign; equivalent Node-script invocation owned; unresolved coordinates unknown; no stored-path rewriting or unsupported runtime-affinity claim.

Additional context

This is a related producing-boundary finding from the #4847/#4895 audit. Fixing it does not provide a stable version-manager registration command. Native realpath API reference: https://nodejs.org/docs/latest-v24.x/api/fs.html#fsrealpathsyncnativepath-options .

Originally created by @morluto on GitHub (Oct 17, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/4896 ### Before submitting - [x] Searched related reports and PRs; #4895 covers unresolved aliases and #4847 stable version-manager launchers. - [x] No credentials, private target paths, or sensitive data included. ### Area Setup, packaging, or upgrade ### Observed behavior Executed owned temporary fixtures on Node24.18.0/macOS arm64 while auditing the identity owner based on 01cdbbdc5. A direct executable path containing a symlink followed by `..` runs the foreign fixture, but the classifier returns `owned` because it applies lexical `path.resolve` before inspecting the filesystem. The Node-script form is a separate control: Node itself normalizes its script argument and runs the current fixture, so its owned classification is correct. Native executable coordinates and Node script arguments must retain their different resolution semantics. ### Reproduction Create `root/entry.mjs` printing `current`; `root/other/entry.mjs` is an executable shell fixture printing `foreign`; and `root/link -> root/other/child`. Let `candidate = root/link/../entry.mjs`. - `execFileSync(candidate)` executes the foreign shell fixture; the classifier for `[candidate, "mcp"]` returns `owned`, expected `foreign`. - `execFileSync(process.execPath, [candidate])` executes the current Node fixture; `[process.execPath, candidate, "mcp"]` is correctly owned. - Kernel-backed reads observe different files. `realpathSync.native` reports different paths; legacy `realpathSync` reports equal paths on the tested Node build. Merely removing the initial `path.resolve` while retaining the legacy resolver is insufficient. Temporary files were removed after execution. No external program or real agent configuration was changed. ### Expected behavior Use filesystem resolution for native executable coordinates. Model Node's script-argument selection separately, preserve configured values, and grant ownership only from the applicable interpretation. Failed identity lookup remains unknown (#4895). ### Impact and scope Observed: the canonical ownership classifier grants a false positive for the direct executable. Source-derived: uninstall and maintenance use this positive decision to select registrations, so an unrelated registration can be admitted for mutation. No destructive public workflow has been run at report creation; a controlled public uninstall regression is proposed. Real-world frequency and native Windows/Linux behavior are NOT_ENOUGH_INFO. ### REA version 6.5.0; normalizing identity rule present at 01cdbbdc556262c47d04a5b3391dd9c17946d3fc; observed in the working-tree build based on that revision. ### Runtime and platform Node24.18.0, macOS arm64; own shell/Node fixtures only. ### Target and artifact context Owned launcher fixture files/symlinks; no reverse-engineering target. ### Interface Package or setup ### Earliest failure stage Setup or provider admission ### Relevant output or evidence Direct executable: runs foreign fixture, classification owned. Node script argument: runs current fixture, classification owned. `readFileSync(candidate)` and `readFileSync(current)` return different bytes. [Owning normalization](https://github.com/morluto/rea/blob/01cdbbdc556262c47d04a5b3391dd9c17946d3fc/src/application/ClientRegistrationIdentity.ts#L120). ### Typed outcome or recovery expected Direct path foreign; equivalent Node-script invocation owned; unresolved coordinates unknown; no stored-path rewriting or unsupported runtime-affinity claim. ### Additional context This is a related producing-boundary finding from the #4847/#4895 audit. Fixing it does not provide a stable version-manager registration command. Native realpath API reference: https://nodejs.org/docs/latest-v24.x/api/fs.html#fsrealpathsyncnativepath-options .
bsakaguchi 2026-10-31 00:35:16 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

@morluto commented on GitHub (Oct 17, 2026):

Fixed in 19329e43bb on main.

Registration identity now has one owner across doctor, maintenance and uninstall. Failed launcher resolution remains unknown. Native filesystem traversal is separate from Node script-argument normalization; ambiguous direct launchers remain unknown and cannot authorize removal. The duplicate boolean ownership parser was removed.

Validation: 183 focused tests passed, 2 Windows cases skipped; check:fast, docs:check and the pre-push gate passed. All five new public regressions fail on the baseline; two existing valid-alias controls pass there. One isolated baseline regression actually removed a foreign fixture registration; the fix preserves its exact bytes. An additional authored Node-shebang control confirmed divergent launch semantics on macOS arm64 / Node 24.18.0. Two source reviews found no remaining blocker.

No native Windows/Linux or real mise upgrade was exercised. The separate stable mise launcher request remains open in #4847.

<!-- gh-comment-id:6242120666 --> @morluto commented on GitHub (Oct 17, 2026): Fixed in 19329e43bb38ca9d64512d801b25abcb188d2512 on main. Registration identity now has one owner across doctor, maintenance and uninstall. Failed launcher resolution remains unknown. Native filesystem traversal is separate from Node script-argument normalization; ambiguous direct launchers remain unknown and cannot authorize removal. The duplicate boolean ownership parser was removed. Validation: 183 focused tests passed, 2 Windows cases skipped; check:fast, docs:check and the pre-push gate passed. All five new public regressions fail on the baseline; two existing valid-alias controls pass there. One isolated baseline regression actually removed a foreign fixture registration; the fix preserves its exact bytes. An additional authored Node-shebang control confirmed divergent launch semantics on macOS arm64 / Node 24.18.0. Two source reviews found no remaining blocker. No native Windows/Linux or real mise upgrade was exercised. The separate stable mise launcher request remains open in #4847.
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#3039
No description provided.