Skip to content

fix(runtime-host): gate Windows Local Owner authority - #3179

Merged
M4n5ter merged 1 commit into
mainfrom
fix/windows-local-ipc-trust
Aug 18, 2026
Merged

fix(runtime-host): gate Windows Local Owner authority#3179
M4n5ter merged 1 commit into
mainfrom
fix/windows-local-ipc-trust

Conversation

@M4n5ter

@M4n5ter M4n5ter commented Aug 18, 2026

Copy link
Copy Markdown
Member

Summary

English

Local IPC no longer grants Local Owner authority to connections opened before the endpoint trust boundary is established. Runtime Host changes now also run a blocking Windows check that admits the current user and attempts the same duplex named-pipe connection under a separate standard-user token.

The real Windows check confirms that the platform boundary denies a foreign standard user, so no native helper or additional authentication state is required.

简体中文

Local IPC 不再向 endpoint 信任边界建立前打开的连接授予 Local Owner authority。Runtime Host 变更现在还会运行 blocking Windows 检查:确认当前用户可以连接,并使用独立标准用户 token 尝试相同的双向 named-pipe 连接。

真实 Windows 检查已确认平台边界会拒绝其他标准用户,因此不需要 native helper 或额外认证状态。

Refs #2522

Verification

English
  • npm run build:test
  • npm --workspace @maka/runtime-host run typecheck
  • npm --workspace @maka/runtime-host run test:dist — 962 passed
  • Biome check and git diff --check
  • Windows cross-user admission — passed
简体中文
  • npm run build:test
  • npm --workspace @maka/runtime-host run typecheck
  • npm --workspace @maka/runtime-host run test:dist — 962 passed
  • Biome check 与 git diff --check
  • Windows 跨用户 admission — passed

AI use

  • No generative tool made a substantive contribution
  • Generative tooling made a substantive contribution

Tool(s) and scope: OpenAI Codex implemented the listener gate, Windows trust harness, CI wiring, and concise architecture updates under maintainer direction.

Checklist

  • Tests cover the change and fail without it
  • Lint, format, typecheck and the affected suites pass locally

Does this PR entail a change in behavior?

  • Yes — described under Summary above
  • No

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: e23931fa-5b8d-44b1-9dc4-3dafd470754e

📥 Commits

Reviewing files that changed from the base of the PR and between 2713659 and 3636f76.

📒 Files selected for processing (2)
  • .github/workflows/windows-recovery.yml
  • packages/runtime-host/src/__tests__/fixtures/windows-local-ipc-trust-host.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/runtime-host/src/tests/fixtures/windows-local-ipc-trust-host.ts

Included review availability: Your plan includes up to 3 reviews per rolling hour; 0 remain after this review.


📝 Walkthrough

Summary

  • Prevents pre-verification Local IPC connections from receiving Local Owner authority.
  • Retains startup connections until endpoint verification completes, then aborts them.
  • Grants Local Owner authority only to connections accepted after verification.
  • Documents the same-user trust requirement in both architecture documents.
  • Adds a Windows cross-user verification script and CI step.

Design assessment

This change extends the existing Runtime Host listener and endpoint verification flow. It does not create a parallel authentication path.

The solution is the smallest coherent approach shown by the diff. The Windows script adds complexity because it must create a foreign user, impersonate that user, and test the same named-pipe endpoint. This validates the OS boundary without a native helper or additional authentication state.

No changed code or test can be removed without weakening the startup race protection or cross-user regression coverage. The endpoint change is documentation-only apart from the existing hook behavior.

Risks and validation

The main risk is incorrect connection handling during the interval before endpoint verification. The listener now retains and aborts those connections instead of accepting them.

The Windows verification also depends on temporary-user creation, C# impersonation, process startup, timeout handling, and cleanup.

The PR objectives report successful build, typecheck, 962 distribution tests, Biome, git diff --check, and the Windows cross-user admission check. These results are unverified here because direct command evidence is unavailable.

Review-relevant risks

  • The diff changes user-visible security behavior: pre-verification Local IPC connections no longer receive Local Owner authority. Security-sensitive behavior requires independent human review under repository policy.
  • The diff changes the Local IPC authority contract and its documented security boundary. Contract changes require independent human review under repository policy.
  • The diff adds Windows CI verification and temporary local-user handling. Changes to CI and governance controls require independent human review under repository policy.

The person performing the merge must review the final diff. A maintainer makes the final determination.

Walkthrough

The Runtime Host now defers Windows Local IPC admission until endpoint verification. A Windows fixture and PowerShell probe verify same-user acceptance and foreign-user denial. Windows CI runs the verification after building test artifacts.

Changes

Windows Local IPC trust

Layer / File(s) Summary
IPC trust boundary
packages/runtime-host/src/control/endpoint.ts, packages/runtime-host/src/server/local-ipc-listener.ts, docs/architecture/runtime-host-architecture.md, docs/architecture/runtime-host-architecture.zh-CN.md
Startup connections remain pending until endpoint verification completes. The listener aborts those connections and accepts later connections with local-owner authority. The endpoint comments and architecture documentation describe the same-user trust requirement.
Windows trust probe
packages/runtime-host/src/__tests__/fixtures/windows-local-ipc-trust-host.ts, scripts/windows-runtime-host-local-ipc-trust.ps1
The fixture exposes a named pipe and reports connection authority. The script probes current-user acceptance, foreign-user denial, process readiness, and cleanup.
CI trust lane
.github/workflows/windows-recovery.yml
The Windows recovery workflow runs the Local IPC trust verification script after building test artifacts.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Merge Risk: ⚪ Minimal · up to 3636f

The change gates Windows Local Owner authority until endpoint trust is established and adds cross-user validation; no actionable merge-blocking risk remains after normal checks and review.

Suggested reviewers: liugddx

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly identifies the main change: gating Windows Local Owner authority in Runtime Host.
Description check ✅ Passed The description covers the summary, verification results, AI use, behavior change, and related issue; the test-coverage checkbox remains unchecked.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Ai Use Disclosure ✅ Passed The PR selects generative tooling, names OpenAI Codex and its scope, and its sole introduced commit has the standalone trailer Generated-by: Codex, consistent with the disclosure.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/windows-local-ipc-trust

Comment @coderabbitai help to get the list of available commands.

@M4n5ter
M4n5ter force-pushed the fix/windows-local-ipc-trust branch 2 times, most recently from 2713659 to 8da31fd Compare August 18, 2026 02:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
packages/runtime-host/src/__tests__/fixtures/windows-local-ipc-trust-host.ts (1)

23-26: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Release stdin so the fixture exits by itself.

process.stdin.resume() keeps a referenced handle on the event loop. After closeAdmission() and cleanup(), that handle stays active, so the process does not exit. The PowerShell script then waits 5000 ms in WaitForExit, calls Kill($true), and logs a non-zero exit code as a warning. Pause or unref stdin after the await to keep the exit clean.

♻️ Proposed fix
 process.stdin.resume();
 await once(process.stdin, 'data');
+process.stdin.pause();
+process.stdin.unref();
 await listener.closeAdmission();
 await listener.cleanup();
scripts/windows-runtime-host-local-ipc-trust.ps1 (1)

103-105: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Silence the PSScriptAnalyzer error for the ephemeral CI password.

PSScriptAnalyzer reports PSAvoidUsingConvertToSecureStringWithPlainText as an error on line 105. The password is generated per run for a throwaway local account, so the finding is acceptable, but an unsuppressed error can fail a lint lane. Add a scoped suppression with the reason.

♻️ Proposed suppression
+[Diagnostics.CodeAnalysis.SuppressMessageAttribute(
+  'PSAvoidUsingConvertToSecureStringWithPlainText',
+  '',
+  Justification = 'Ephemeral per-run local account password for cross-user trust verification.'
+)]
+param()
+
 $ErrorActionPreference = 'Stop'

Source: Linters/SAST tools

.github/workflows/ci.yml (1)

153-157: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Scope the job token permissions.

zizmor reports that this job inherits default permissions. The lane only checks out code and runs a build plus a script. Set permissions: {} on the job to drop the token grant.

🔒️ Proposed fix
   windows_local_ipc_trust:
     needs: changes
     if: needs.changes.outputs.runtime_host == 'true'
     runs-on: windows-2025
+    permissions: {}
     steps:

Source: Linters/SAST tools


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0803846d-8d83-442a-9fdc-e452eed7308d

📥 Commits

Reviewing files that changed from the base of the PR and between be3fdd1 and 2713659.

📒 Files selected for processing (7)
  • .github/workflows/ci.yml
  • docs/architecture/runtime-host-architecture.md
  • docs/architecture/runtime-host-architecture.zh-CN.md
  • packages/runtime-host/src/__tests__/fixtures/windows-local-ipc-trust-host.ts
  • packages/runtime-host/src/control/endpoint.ts
  • packages/runtime-host/src/server/local-ipc-listener.ts
  • scripts/windows-runtime-host-local-ipc-trust.ps1

Included review availability: Your plan includes up to 3 reviews per rolling hour; 0 remain after this review.

Local IPC previously accepted connections before endpoint verification, while the Windows named-pipe boundary had no blocking cross-user evidence. Gate startup connections until the endpoint is trusted and require a real Windows foreign-user admission check for Runtime Host changes.

Generated-by: Codex
@M4n5ter
M4n5ter force-pushed the fix/windows-local-ipc-trust branch from 8da31fd to 3636f76 Compare August 18, 2026 02:10
@M4n5ter
M4n5ter marked this pull request as ready for review August 18, 2026 02:15
@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

Gate Windows Local Owner authority behind IPC endpoint trust

🐞 Bug fix 🧪 Tests 📝 Documentation ⚙️ Configuration changes 🕐 40+ Minutes

Grey Divider

AI Description

• Blocks pre-verification IPC connections from receiving Local Owner authority.
• Verifies Windows named pipes admit the current user and reject foreign standard users.
• Documents and enforces the trust boundary through blocking Windows CI.
Diagram

sequenceDiagram
  actor Early as Early Client
  participant Listener as Local Listener
  participant Endpoint as OS Endpoint
  actor Owner as Current User
  actor Foreign as Foreign User
  Listener->>Endpoint: Start listening
  Early->>Endpoint: Connect during startup
  Endpoint->>Listener: Queue transport
  Listener->>Endpoint: Verify trust boundary
  Endpoint-->>Listener: Trust established
  Listener--xEarly: Abort pending transport
  Owner->>Endpoint: Open duplex pipe
  Endpoint->>Listener: Admit connection
  Listener-->>Owner: Local Owner authority
  Foreign->>Endpoint: Open duplex pipe
  Endpoint--xForeign: Access denied
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Explicit native pipe ACL
  • ➕ Defines the Windows security descriptor directly instead of relying on the process-token DACL.
  • ➕ Makes intended principals explicit at endpoint creation time.
  • ➖ Requires a native helper or FFI surface with additional packaging and maintenance.
  • ➖ Introduces platform-specific security code when the existing OS default already enforces the requirement.
2. Application-level authentication
  • ➕ Provides an authorization layer independent of named-pipe ACL behavior.
  • ➕ Could express richer identities than same-user ownership.
  • ➖ Requires credential generation, distribution, rotation, and protocol state.
  • ➖ Allows foreign clients to reach more of the transport stack before rejection.

Recommendation: Keep the PR’s OS-enforced boundary, startup admission gate, and real cross-user CI probe. It fixes the authority race without adding authentication state or native distribution requirements; explicit ACL construction should only be reconsidered if supported Windows environments stop providing the verified default-DACL behavior.

Files changed (7) +237 / -6

Bug fix (1) +12 / -5
local-ipc-listener.tsReject connections opened before endpoint verification +12/-5

Reject connections opened before endpoint verification

• Defers admission while the endpoint trust boundary is being prepared, then aborts every startup transport rather than granting it Local Owner authority. Post-verification connections continue through a shared guarded admission helper.

packages/runtime-host/src/server/local-ipc-listener.ts

Tests (2) +215 / -0
windows-local-ipc-trust-host.tsAdd Windows Local IPC trust host fixture +27/-0

Add Windows Local IPC trust host fixture

• Starts a real Runtime Host listener and reports readiness and accepted principal kinds over stdout. It supports external current-user and cross-user named-pipe probes and performs orderly cleanup.

packages/runtime-host/src/tests/fixtures/windows-local-ipc-trust-host.ts

windows-runtime-host-local-ipc-trust.ps1Add real Windows cross-user named-pipe probe +188/-0

Add real Windows cross-user named-pipe probe

• Creates a temporary standard user, starts the Runtime Host fixture, and confirms the current user receives Local Owner authority. An impersonated C# probe attempts the same duplex connection as the foreign user and requires an access-denied result before cleaning up all resources.

scripts/windows-runtime-host-local-ipc-trust.ps1

Documentation (3) +6 / -1
runtime-host-architecture.mdDocument Local Owner endpoint trust requirement +1/-0

Document Local Owner endpoint trust requirement

• States that Local IPC may grant Local Owner authority only after the operating-system endpoint establishes a same-user trust boundary.

docs/architecture/runtime-host-architecture.md

runtime-host-architecture.zh-CN.mdDocument endpoint trust requirement in Chinese +1/-0

Document endpoint trust requirement in Chinese

• Adds the same Local Owner and same-user endpoint trust guarantee to the Simplified Chinese architecture documentation.

docs/architecture/runtime-host-architecture.zh-CN.md

endpoint.tsRecord the Windows named-pipe DACL trust contract +4/-1

Record the Windows named-pipe DACL trust contract

• Documents that Node creates the Windows pipe using the process token’s default DACL and that blocking cross-user CI verifies duplex access isolation.

packages/runtime-host/src/control/endpoint.ts

Other (1) +4 / -0
windows-recovery.ymlAdd blocking Windows IPC trust verification +4/-0

Add blocking Windows IPC trust verification

• Runs the Runtime Host Local IPC trust probe after building test artifacts. This prevents Windows trust-boundary regressions from merging.

.github/workflows/windows-recovery.yml

@M4n5ter
M4n5ter merged commit fb16d81 into main Aug 18, 2026
12 checks passed
@M4n5ter
M4n5ter deleted the fix/windows-local-ipc-trust branch August 18, 2026 02:20
@qodo-code-review

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Foreign read connections remain allowed 🐞 Bug ⛨ Security
Description
Disposition: Fix now. The Windows branch performs no endpoint hardening and tests only duplex
denial, although the default named-pipe DACL permits Everyone read access; a foreign user can
therefore establish read-only connections that receive Local Owner authority at the listener and
occupy the unbounded handshake set until timeout, violating the documented same-user boundary and
enabling connection-flood denial of service.
Code

packages/runtime-host/src/control/endpoint.ts[R39-42]

+      async prepareAfterListen() {
+        // Node creates the pipe with the process token's default DACL. The
+        // blocking cross-user CI pins that a foreign user cannot open it duplex.
+      },
Relevance

●● Moderate

Security concern is substantive, but history lacks close endpoint or named-pipe rejection precedent.

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The changed Windows endpoint explicitly relies on the process token's default DACL and performs no
verification. Microsoft documents that a named pipe's default descriptor grants read access to
Everyone and anonymous users; the probe requests only PipeDirection.InOut, while the listener
assigns Local Owner authority to every connected transport and the kernel tracks handshaking
transports without an admission bound.

packages/runtime-host/src/control/endpoint.ts[35-44]
scripts/windows-runtime-host-local-ipc-trust.ps1[51-79]
packages/runtime-host/src/server/local-ipc-listener.ts[22-36]
packages/runtime-host/src/server/host-kernel.ts[335-342]
🌐 Microsoft states that the default named-pipe security descriptor grants read access to Everyone and the anonymous account.

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The Windows Local IPC endpoint relies on the default named-pipe DACL and verifies only that foreign users cannot open it duplex. Windows' default descriptor still grants read access to Everyone, so foreign read-only connections can reach the listener and consume Runtime Host handshake resources.

## Issue Context
Reuse the existing `prepareAfterListen()` trust-boundary seam to enforce and verify a current-user-only pipe ACL. Deleting the Windows path cannot satisfy the required Local IPC behavior, and protocol authority cannot be consolidated safely while foreign connections still reach the endpoint; explicit endpoint hardening is therefore required. Extend the Windows probe to test every relevant access direction, including read-only access, rather than introducing a separate authority mechanism.

## Fix Focus Areas
- packages/runtime-host/src/control/endpoint.ts[39-42]
- packages/runtime-host/src/server/local-ipc-listener.ts[22-36]
- scripts/windows-runtime-host-local-ipc-trust.ps1[51-79]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Failed startup skips user cleanup 🐞 Bug ☼ Reliability
Description
Disposition: Fix now. If Process.Start() fails after $fixture is assigned, the finally block
accesses HasExited on an unstarted process and can mask the original error before
Remove-LocalUser executes, leaving the generated Windows account behind.
Code

scripts/windows-runtime-host-local-ipc-trust.ps1[R169-172]

+  if ($null -ne $fixture) {
+    if (-not $fixture.HasExited) {
+      $fixture.StandardInput.WriteLine('close')
+      $fixture.StandardInput.Flush()
Relevance

●●● Strong

Unstarted-process cleanup masking startup failures is a deterministic reliability bug; historical
cleanup feedback is generally accepted.

PR-#3169

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The script assigns a newly constructed process to $fixture before calling Start(), explicitly
throws when startup returns false, and then unconditionally reads HasExited whenever $fixture is
non-null. Temporary-user deletion is later in the same finally, so an exception during process
cleanup bypasses it; past PR #3111 records the same cleanup-order failure pattern.

scripts/windows-runtime-host-local-ipc-trust.ps1[103-115]
scripts/windows-runtime-host-local-ipc-trust.ps1[127-131]
scripts/windows-runtime-host-local-ipc-trust.ps1[168-186]
PR-#3111

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The fixture variable is assigned before process startup succeeds, but cleanup assumes every non-null fixture has an associated process. Accessing `HasExited` after `Start()` fails can throw and prevent deletion of the temporary local user.

## Issue Context
Make the smallest local correction: track successful process startup or assign the cleanup-owned fixture only after startup succeeds, dispose an unstarted process separately, and place local-user deletion in an independent `finally` so process-cleanup failures cannot skip it. The small startup-state branch is necessary because `System.Diagnostics.Process` does not expose a safe `HasExited` value before successful startup.

## Fix Focus Areas
- scripts/windows-runtime-host-local-ipc-trust.ps1[106-107]
- scripts/windows-runtime-host-local-ipc-trust.ps1[127-131]
- scripts/windows-runtime-host-local-ipc-trust.ps1[168-186]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context
✅ Web pages:
  +16 more
Review mode: ⚖️ Balanced: This security-sensitive Windows IPC authority change modifies admission timing, endpoint trust assumptions, and a cross-user verification harness; it warrants a careful single-pass review, though the scope is not dense enough to justify redundant extended passes.

Grey Divider

ⓘ  1 issues published inline · 2 in summary

Tip of the day
💡 Did you know, you can keep summaries lean with Finding overflow, which tucks the rest behind 'View more'

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment on lines +39 to +42
async prepareAfterListen() {
// Node creates the pipe with the process token's default DACL. The
// blocking cross-user CI pins that a foreign user cannot open it duplex.
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Foreign read connections remain allowed 🐞 Bug ⛨ Security

Disposition: Fix now. The Windows branch performs no endpoint hardening and tests only duplex
denial, although the default named-pipe DACL permits Everyone read access; a foreign user can
therefore establish read-only connections that receive Local Owner authority at the listener and
occupy the unbounded handshake set until timeout, violating the documented same-user boundary and
enabling connection-flood denial of service.
Agent Prompt
## Issue description
The Windows Local IPC endpoint relies on the default named-pipe DACL and verifies only that foreign users cannot open it duplex. Windows' default descriptor still grants read access to Everyone, so foreign read-only connections can reach the listener and consume Runtime Host handshake resources.

## Issue Context
Reuse the existing `prepareAfterListen()` trust-boundary seam to enforce and verify a current-user-only pipe ACL. Deleting the Windows path cannot satisfy the required Local IPC behavior, and protocol authority cannot be consolidated safely while foreign connections still reach the endpoint; explicit endpoint hardening is therefore required. Extend the Windows probe to test every relevant access direction, including read-only access, rather than introducing a separate authority mechanism.

## Fix Focus Areas
- packages/runtime-host/src/control/endpoint.ts[39-42]
- packages/runtime-host/src/server/local-ipc-listener.ts[22-36]
- scripts/windows-runtime-host-local-ipc-trust.ps1[51-79]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant