[GH-ISSUE #5238] [Bug] Native ownership verification trusts stale process-table UID across generations #3205

Closed
opened 2026-10-31 00:37:49 +00:00 by bsakaguchi · 2 comments
Owner

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

Before submitting

  • Searched open and closed issues for UID, withheld environments, and stale process ownership; reviewed #1056, #2035, and #5206 for overlap.
  • No credentials, environment contents, or private target data are included.

Area / interface / failure stage

Process capture or runtime observation; shared production ownership verification; cleanup/lifecycle.

Observed behavior

A controlled call to verifyNoTokenOwnedProcesses on main reports cleaned: true when a candidate's token is unreadable and its only foreign-user evidence is UID from an earlier process-table row. The native identity observations establish the current generation, but do not bind that row's UID to it.

Reproduction

Executed a reduced Node/tsx probe against source revision a0edd145d31ffeb9f022c25ec9e9131083f563d5, Node 24.18.0, macOS arm64. No target process was launched or signaled. The injected production ProcessOwnershipHost supplies:

  1. A live row for PID/PGID 906, parent 1, with stale foreign UID 0 (caller UID 501).
  2. Matching native start identities before and after the token reads for the current generation. The controlled current native UID is 501; main does not consume a generation-bound UID fact.
  3. Token result {state:"unavailable",reason:"EINVAL"} on every attempt, an empty capture baseline, and scope anchored at launcher/group 100.

Actual output after two identity reads and four token reads:

{"cleaned":true,"signaled":false,"unverified":[{"pid":906,"diagnostic":"EINVAL"}]}

Expected behavior

An earlier row's UID must not establish that a newly observed generation is foreign. Bind UID to the current native identity observation, or preserve the token/identity uncertainty. Repository guidance requires unresolved identity/applicability to remain unknown and consumers to use facts from their owning boundary.

Impact and scope

The probe demonstrates a provenance error and a completion exemption based on stale metadata. Actual PID reuse, credential transitions, OS permission denial, and real-provider impact were not reproduced. Frequency in real workloads: NOT_ENOUGH_INFO. No unrelated-process signaling is claimed.

environmentWithheldFromInspection and its scanner consumer use ProcessTableEntry.uid separately from native generation checks. #1056 and #2035 establish the need to preserve explicitly withheld unrelated observations; this report concerns the generation provenance of the UID exemption. #5206 concerns losing reparented descendants during refresh.

Originally created by @morluto on GitHub (Oct 19, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5238 ### Before submitting - [x] Searched open and closed issues for UID, withheld environments, and stale process ownership; reviewed #1056, #2035, and #5206 for overlap. - [x] No credentials, environment contents, or private target data are included. ### Area / interface / failure stage Process capture or runtime observation; shared production ownership verification; cleanup/lifecycle. ### Observed behavior A controlled call to `verifyNoTokenOwnedProcesses` on main reports `cleaned: true` when a candidate's token is unreadable and its only foreign-user evidence is UID from an earlier process-table row. The native identity observations establish the current generation, but do not bind that row's UID to it. ### Reproduction Executed a reduced Node/tsx probe against source revision `a0edd145d31ffeb9f022c25ec9e9131083f563d5`, Node 24.18.0, macOS arm64. No target process was launched or signaled. The injected production `ProcessOwnershipHost` supplies: 1. A live row for PID/PGID 906, parent 1, with stale foreign UID 0 (caller UID 501). 2. Matching native start identities before and after the token reads for the current generation. The controlled current native UID is 501; main does not consume a generation-bound UID fact. 3. Token result `{state:"unavailable",reason:"EINVAL"}` on every attempt, an empty capture baseline, and scope anchored at launcher/group 100. Actual output after two identity reads and four token reads: ```json {"cleaned":true,"signaled":false,"unverified":[{"pid":906,"diagnostic":"EINVAL"}]} ``` ### Expected behavior An earlier row's UID must not establish that a newly observed generation is foreign. Bind UID to the current native identity observation, or preserve the token/identity uncertainty. Repository guidance requires unresolved identity/applicability to remain unknown and consumers to use facts from their owning boundary. ### Impact and scope The probe demonstrates a provenance error and a completion exemption based on stale metadata. Actual PID reuse, credential transitions, OS permission denial, and real-provider impact were not reproduced. Frequency in real workloads: `NOT_ENOUGH_INFO`. No unrelated-process signaling is claimed. ### Relevant source and related reports [`environmentWithheldFromInspection` and its scanner consumer](https://github.com/morluto/rea/blob/a0edd145d31ffeb9f022c25ec9e9131083f563d5/src/process/ProcessOwnership.ts#L910) use `ProcessTableEntry.uid` separately from native generation checks. #1056 and #2035 establish the need to preserve explicitly withheld unrelated observations; this report concerns the generation provenance of the UID exemption. #5206 concerns losing reparented descendants during refresh.
bsakaguchi 2026-10-31 00:37:49 +00:00
  • closed this issue
  • added the
    triage
    bug
    labels
Author
Owner

@Vedant1521 commented on GitHub (Oct 19, 2026):

Hi @morluto, I'd like to take a look at this if you aren't already working on a patch. From the description, it looks like environmentWithheldFromInspection should consume a generation-bound UID from the native start-identity observation (or fall back to unresolved uncertainty when only an unbound ProcessTableEntry.uid is present) rather than trusting the initial table row's uid. Let me know if it's open to pick up!

<!-- gh-comment-id:6266561048 --> @Vedant1521 commented on GitHub (Oct 19, 2026): Hi @morluto, I'd like to take a look at this if you aren't already working on a patch. From the description, it looks like environmentWithheldFromInspection should consume a generation-bound UID from the native start-identity observation (or fall back to unresolved uncertainty when only an unbound ProcessTableEntry.uid is present) rather than trusting the initial table row's uid. Let me know if it's open to pick up!
Author
Owner

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

Fixed on main in 49e67aa1d. Native ownership scans now use effective UID from the native generation observation, so an older process-table UID cannot exempt a current unreadable token. Unavailable identity remains unresolved, and one run-scoped owner retains related generations and failed identity lookups through omissions and cleanup retries. Signals still require fresh token and native group proof.

Validation on macOS arm64 / Node 24.18.0: npm run check, npm run docs:check, and test discovery passed. Ownership/consumer coverage totals 513 passed and 1 skipped across 35 focused files, including compiled Darwin helper controls, actual owned Node child cleanup, CLI/MCP capture, and retained cleanup retry. The stale-UID controlled probe changes from cleaned:true with an unverified PID to cleaned:false / environment-unreadable.

The probe did not launch or signal a target, and does not reproduce actual OS PID reuse, credential changes, or permission races. Native Linux and Windows qualification remains unverified; #4322 and #5206 remain open for their wider cases.

<!-- gh-comment-id:6266791399 --> @morluto commented on GitHub (Oct 19, 2026): Fixed on main in [49e67aa1d](https://github.com/morluto/rea/commit/49e67aa1d963bda337c261f4813ecb7128e2a50c). Native ownership scans now use effective UID from the native generation observation, so an older process-table UID cannot exempt a current unreadable token. Unavailable identity remains unresolved, and one run-scoped owner retains related generations and failed identity lookups through omissions and cleanup retries. Signals still require fresh token and native group proof. Validation on macOS arm64 / Node 24.18.0: `npm run check`, `npm run docs:check`, and test discovery passed. Ownership/consumer coverage totals 513 passed and 1 skipped across 35 focused files, including compiled Darwin helper controls, actual owned Node child cleanup, CLI/MCP capture, and retained cleanup retry. The stale-UID controlled probe changes from `cleaned:true` with an unverified PID to `cleaned:false` / `environment-unreadable`. The probe did not launch or signal a target, and does not reproduce actual OS PID reuse, credential changes, or permission races. Native Linux and Windows qualification remains unverified; #4322 and #5206 remain open for their wider cases.
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#3205
No description provided.