Skip to content

fix(connection): trust MSIX-packaged wslrelay.exe when Authenticode check fails - #1177

Closed
larroy wants to merge 1 commit into
openclaw:mainfrom
larroy:fix/wslrelay-msix-authenticode-fallback-main
Closed

fix(connection): trust MSIX-packaged wslrelay.exe when Authenticode check fails#1177
larroy wants to merge 1 commit into
openclaw:mainfrom
larroy:fix/wslrelay-msix-authenticode-fallback-main

Conversation

@larroy

@larroy larroy commented Aug 19, 2026

Copy link
Copy Markdown

Problem

Setup fails on machines running the modern MSIX-distributed WSL (Program Files\WSL, e.g. the Store/GitHub-released package) with:

Loopback port 18789 listener verification failed: wslrelay (PID ...): WSL relay Authenticode verification failed (Unsigned).

MSIX packages don't embed per-file Authenticode/catalog signatures on their EXEs — trust is established at the package level instead (verified by Windows at install time). So wslrelay.exe, wsl.exe, wslhost.exe, etc. from this distribution report Unsigned via WinVerifyTrust/FileSignatureInfo, even though they're genuine, unmodified Microsoft binaries (confirmed via Get-AppxPackage: Publisher = CN=Microsoft Corporation, O=Microsoft Corporation, ...).

Fix

Add a fallback to WindowsAuthenticodeVerifier.VerifyMicrosoftSignedFile: when the primary Authenticode/catalog check fails and the file is wslrelay.exe, corroborate trust via the installed AppX package instead of rejecting outright. The fallback requires all of:

  • Exact match on the known WSL package family name MicrosoftCorporationII.WindowsSubsystemForLinux_8wekyb3d8bbwe (the suffix is derived from the publisher's signing certificate, so an impostor package re-signed with a different cert would get a different family name).
  • A real SignatureKind (not None) — proves Windows cryptographically validated the package at install time.
  • A Microsoft publisher, reusing the existing HasMicrosoftPublisherIdentity check unchanged.

Looked up via a powershell.exe -Command "Get-AppxPackage ... | ConvertTo-Json" shell-out, matching this file's existing pattern for invoking schtasks.exe/wsl.exe elsewhere in ManagedLocalGatewayPortProvenanceService.cs.

The primary Authenticode/catalog check is unchanged, always runs first, and is never bypassed — the fallback only narrows scope to wslrelay.exe and never weakens the trust bar for any other binary. No .csproj/TFM changes; no changes to the canonical-path allowlist.

Testing

  • dotnet build src/OpenClaw.Connection/OpenClaw.Connection.csproj — succeeds, 0 warnings/errors.
  • dotnet test tests/OpenClaw.Connection.Tests/OpenClaw.Connection.Tests.csproj — 638/638 passing, including 6 new tests covering: trusted-via-fallback, no-package-found, family-name mismatch, unsigned package, non-Microsoft publisher, and a regression test proving the fallback is never consulted when Authenticode already succeeds.

🤖 Generated with Claude Code

…heck fails

Modern WSL distributes as an MSIX package (Program Files\WSL /
WindowsApps), which doesn't embed per-file Authenticode/catalog
signatures on its EXEs -- trust is established at the package level
instead. This caused genuine Microsoft wslrelay.exe binaries to be
rejected during setup's loopback listener provenance check with
"WSL relay Authenticode verification failed (Unsigned)".

Add a fallback in WindowsAuthenticodeVerifier: when the classic
Authenticode check fails and the file is wslrelay.exe, corroborate
trust via the installed AppX package instead. Requires an exact match
on the known WSL package family name (MicrosoftCorporationII.WindowsSubsystemForLinux_8wekyb3d8bbwe,
whose suffix is derived from the publisher's signing cert), a real
SignatureKind, and a Microsoft publisher (reusing the existing
HasMicrosoftPublisherIdentity check). Looked up via a PowerShell
Get-AppxPackage shell-out, matching this file's existing pattern for
invoking schtasks.exe/wsl.exe.

The primary Authenticode/catalog check is unchanged and always
consulted first; the fallback narrows to wslrelay.exe specifically and
never weakens the trust bar for any other binary.
@clawsweeper

clawsweeper Bot commented Aug 19, 2026

Copy link
Copy Markdown

🦞👀
ClawSweeper picked this up.

Pull request received. I will update this pull request when review starts.

@clawsweeper clawsweeper Bot added merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels Aug 19, 2026
@clawsweeper

clawsweeper Bot commented Aug 19, 2026

Copy link
Copy Markdown

Codex review: needs real behavior proof before merge. Reviewed August 21, 2026, 2:28 PM ET / 18:28 UTC.

ClawSweeper review

What this changes

This PR adds an AppX package-metadata fallback for wslrelay.exe when ordinary Authenticode verification fails, plus focused fallback tests.

Merge readiness

Blocked until real behavior proof from a real setup is added - 9 items remain

Keep open. The useful MSIX compatibility goal remains unimplemented on current main, but the unchanged PR fallback still trusts package metadata without proving that the inspected relay belongs to that package, which can weaken the credential-protection boundary.

Priority: P0
Reviewed head: aff4e3917f1d7de97e9e68fe2a638bf96d2542ac

Review scores

Measure Result What it means
Overall readiness 🧂 unranked krab (1/6) The compatibility intent is credible, but an unaddressed credential-boundary flaw and mock-only proof make this patch not ready to merge.
Proof confidence 🧂 unranked krab (1/6) Needs real behavior proof before merge: The PR body reports unit tests only; it has no current-head after-fix trace from an affected MSIX WSL relay through the actual setup/provenance path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Patch quality 🧂 unranked krab (1/6) Security review found an item that needs attention.

Verification

Check Result Evidence
Real behavior Needs proof Needs real behavior proof before merge: The PR body reports unit tests only; it has no current-head after-fix trace from an affected MSIX WSL relay through the actual setup/provenance path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
Evidence reviewed 6 items Current main still rejects a failed file signature: Current main returns an untrusted result whenever the individual-file signature state is not trusted, so the reported compatibility case is not already implemented.
Fallback does not bind metadata to the inspected bytes: The PR consults the fallback for any path named wslrelay.exe and returns its package-metadata result; the package projection contains no installed location, file binding, or path argument.
Caller allows a broad WindowsApps relay path: The current provenance path accepts any wslrelay.exe below Program Files\WindowsApps, then uses the resulting expected-gateway provenance to permit strong credentials.
Findings 2 actionable findings [P1] Bind fallback trust to the inspected relay bytes
[P2] Inject the primary signature result into fallback tests
Security Needs attention Package metadata does not authenticate relay bytes: A path named wslrelay.exe can reach the fallback without being proven to reside in, or be installed by, the trusted package whose metadata is queried.

Live Verification

Command: dotnet test tests/OpenClaw.Connection.Tests/OpenClaw.Connection.Tests.csproj --filter "FullyQualifiedName~VerifyMicrosoftSignedFile"

Result: FAIL (failed) — execution before step 1 run: sh -lc pnpm install --ignore-scripts --frozen-lockfile failed: ! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-11.22.0.tgz

sh -lc pnpm install --ignore-scripts --frozen-lockfile failed: ! Corepack is about to download https://registry.npmjs.org/pnpm/-/pnpm-11.22.0.tgz

Assertions:

  • FAIL expect_output: Test run for

How this fits together

Loopback listener provenance verifies that a local WSL relay actually fronts the managed gateway before shared or bootstrap credentials may be used. The proposed fallback sits between relay-path validation and that credential gate.

flowchart LR
A[Loopback listener] --> B[Relay path review]
B --> C[Authenticode verification]
C -->|Signed| E[WSL gateway provenance]
C -->|Unsigned MSIX relay| D[Package ownership proof]
D --> E
E --> F[Shared credential gate]
Loading

Before merge

  • Add real behavior proof - Needs real behavior proof before merge: The PR body reports unit tests only; it has no current-head after-fix trace from an affected MSIX WSL relay through the actual setup/provenance path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.
  • Bind fallback trust to the inspected relay bytes (P1) - The fallback returns trusted based only on the installed WSL package metadata. The caller accepts any wslrelay.exe under the broad WindowsApps root, so a different unsigned relay can pass this branch while a genuine package is installed. Because this result feeds the shared/bootstrap credential provenance gate, query package location or an equivalent authoritative file binding and reject paths outside it.
  • Inject the primary signature result into fallback tests (P2) - These tests claim to cover failed Authenticode cases but first call the host's real verifier. On a host where C:\Program Files\WSL\wslrelay.exe is signed, the primary branch returns trusted and the negative package assertions fail or do not exercise the fallback. Add a primary-result seam and test the failure branch deterministically.
  • Resolve security concern: Package metadata does not authenticate relay bytes - A path named wslrelay.exe can reach the fallback without being proven to reside in, or be installed by, the trusted package whose metadata is queried.
  • Resolve merge risk (P2) - Merging the current fallback could mark an unrelated unsigned relay under the broad WindowsApps path as trusted whenever genuine WSL package metadata is present, allowing it to participate in the strong-credential provenance path.
  • Resolve merge risk (P1) - No current-head, affected-MSIX-host trace demonstrates the corrected compatibility path or its fail-closed ownership checks.
  • Improve patch quality - Prove package ownership of the exact relay path, including WindowsApps sibling and external-path mismatch rejections.
  • Improve patch quality - Inject the primary Authenticode result so fallback tests do not depend on the host relay signature state.
  • Improve patch quality - Add a redacted current-head trace from an affected MSIX WSL setup/provenance path, then run the required repository validation and focused connection tests.

Findings

  • [P1] Bind fallback trust to the inspected relay bytes — src/OpenClaw.Connection/WindowsAuthenticodeVerifier.cs:56-59
  • [P2] Inject the primary signature result into fallback tests — tests/OpenClaw.Connection.Tests/ManagedLocalGatewayPortProvenanceServiceTests.cs:66-92
  • [high] Package metadata does not authenticate relay bytes — src/OpenClaw.Connection/WindowsAuthenticodeVerifier.cs:59
Agent review details

Security

Needs attention: The package-level fallback can authenticate metadata for a genuine WSL package without authenticating the listener relay bytes that receive trusted provenance.

Review metrics

Metric Value Why it matters
Implementation and test growth production +197/-1, tests +88 The security-sensitive fallback is materially larger than its test coverage and still lacks the required package-to-file binding cases.

Merge-risk options

Maintainer options:

  1. Bind trust to the exact relay (recommended)
    Extend the package lookup and relay inspection to prove package ownership of the canonical listener path, add mismatch rejection coverage, and provide redacted affected-host proof before merge.

Technical review

Best possible solution:

Preserve the compatibility fallback only after it proves the exact listener relay is owned by the trusted installed WSL package and shows that result on an affected MSIX installation.

Do we have a high-confidence way to reproduce the issue?

No. Source proves that a failed individual-file signature is rejected on current main, but this review has no observed affected MSIX relay from the current PR head.

Is this the best way to solve the issue?

No. Package family, publisher, and signature kind alone do not establish that the inspected relay is the package-owned file; exact path and package binding are required.

Full review comments:

  • [P1] Bind fallback trust to the inspected relay bytes — src/OpenClaw.Connection/WindowsAuthenticodeVerifier.cs:56-59
    The fallback returns trusted based only on the installed WSL package metadata. The caller accepts any wslrelay.exe under the broad WindowsApps root, so a different unsigned relay can pass this branch while a genuine package is installed. Because this result feeds the shared/bootstrap credential provenance gate, query package location or an equivalent authoritative file binding and reject paths outside it.
    Confidence: 0.99
  • [P2] Inject the primary signature result into fallback tests — tests/OpenClaw.Connection.Tests/ManagedLocalGatewayPortProvenanceServiceTests.cs:66-92
    These tests claim to cover failed Authenticode cases but first call the host's real verifier. On a host where C:\Program Files\WSL\wslrelay.exe is signed, the primary branch returns trusted and the negative package assertions fail or do not exercise the fallback. Add a primary-result seam and test the failure branch deterministically.
    Confidence: 0.98

Overall correctness: patch is incorrect
Overall confidence: 0.99

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against d3ed6c78bf14.

Labels

Label justifications:

  • P0: This changes the provenance gate that protects shared and bootstrap credentials during managed local setup.
  • merge-risk: 🚨 security-boundary: The fallback can convert untrusted relay bytes into trusted gateway provenance without proving package ownership.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR body reports unit tests only; it has no current-head after-fix trace from an affected MSIX WSL relay through the actual setup/provenance path. After adding proof, update the PR body; ClawSweeper should re-review automatically. If it does not, the PR author or someone with repository write access can comment @clawsweeper re-review.

Evidence

Security concerns:

  • [high] Package metadata does not authenticate relay bytes — src/OpenClaw.Connection/WindowsAuthenticodeVerifier.cs:59
    A path named wslrelay.exe can reach the fallback without being proven to reside in, or be installed by, the trusted package whose metadata is queried.
    Confidence: 0.99

Acceptance criteria:

  • [P1] ./build.ps1.
  • [P1] dotnet test ./tests/OpenClaw.Shared.Tests/OpenClaw.Shared.Tests.csproj --no-restore.
  • [P1] dotnet test ./tests/OpenClaw.Tray.Tests/OpenClaw.Tray.Tests.csproj --no-restore.
  • [P1] dotnet test tests/OpenClaw.Connection.Tests/OpenClaw.Connection.Tests.csproj.
  • [P1] Redacted affected-MSIX-host trace showing relay path, package ownership binding, failed individual-file signature, and successful expected-gateway provenance after the repair.

What I checked:

Likely related people:

  • shanselman: Current-main blame attributes both the canonical relay-path policy and the strong-credential gate to Scott Hanselman, who also supplied the concrete package-ownership review requirements. (role: original provenance author and recent security reviewer; confidence: high; commits: 4206611f2b2e; files: src/OpenClaw.Connection/ManagedLocalGatewayPortProvenanceService.cs, src/OpenClaw.Connection/WindowsAuthenticodeVerifier.cs)

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Workflow

  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

History

Review history (1 earlier review cycle)
  • reviewed 2026-08-19T16:46:28.897Z sha aff4e39 :: needs real behavior proof before merge. :: [P1] Bind the fallback to the inspected relay's package

@shanselman

Copy link
Copy Markdown
Collaborator

The compatibility issue is real: some Store/MSIX WSL installations can report the genuine wslrelay.exe as unsigned at the individual-file layer even though Windows trusted the package at installation.

The current fallback cannot merge because it disconnects the file being trusted from the package being verified. A genuine WSL package can be installed while a different wslrelay.exe under the broad WindowsApps canonical-path rule owns the listener. The fallback validates only the separately queried package family/publisher/signature kind, then trusts the unrelated relay path. This provenance result gates shared/bootstrap credentials, so that is a security-boundary regression rather than only a setup compatibility issue.

Please change the fallback contract to receive the inspected path and prove package ownership:

  1. Keep FileSignatureInfo as the primary path.
  2. Query authoritative package location data in addition to family, publisher, and signature kind.
  3. For WindowsApps layouts, require the inspected canonical path to be under that exact package's installed/effective location.
  4. For the external C:\Program Files\WSL\wslrelay.exe layout, require the exact canonical path, no reparse-point ambiguity, protected SYSTEM/Admin ownership and write ACLs, and a package/file version binding. Fail closed if the external bytes cannot be bound to the installed package.
  5. Add a sibling-WindowsApps relay rejection test and an external-path mismatch rejection test.
  6. Inject the primary Authenticode result into tests. On WSL 2.9.4 here, C:\Program Files\WSL\wslrelay.exe is already validly Microsoft-signed, so the fallback is never called and 4 of the 638 tests fail: no package, family mismatch, unsigned package, and non-Microsoft publisher all unexpectedly return trusted.
  7. Run full required validation and provide redacted current-head proof through an actually affected MSIX WSL setup/provenance path.

Observed on this host:

WSL package: MicrosoftCorporationII.WindowsSubsystemForLinux_2.9.4.0_x64__8wekyb3d8bbwe
Package family: MicrosoftCorporationII.WindowsSubsystemForLinux_8wekyb3d8bbwe
Package install location: C:\Program Files\WindowsApps\MicrosoftCorporationII.WindowsSubsystemForLinux_2.9.4.0_x64__8wekyb3d8bbwe
Relay path: C:\Program Files\WSL\wslrelay.exe
Relay Authenticode: Valid, Microsoft Corporation
Relay file/product version: 2.9.4.0
Relay ACL: writable only by SYSTEM and Administrators; Users and app packages are read/execute

The goal is good. The package-level fallback just needs to prove that the package owns or authoritatively installed the exact relay bytes before those bytes can pass the credential-protection gate.

@shanselman shanselman added the status: 🚢 actively landing A maintainer or agent is actively driving this item through implementation, validation, or merge. label Aug 21, 2026
@shanselman

Copy link
Copy Markdown
Collaborator

Pedro, thank you for finding and addressing the underlying WSL compatibility problem. The important observation in this PR is correct: Windows can trust an MSIX package even when one of its executable files does not present the per-file Authenticode evidence we normally expect from a Win32 binary.

We took this over in maintainer PR #1201 because this check sits on a credential boundary and the remaining work needed fairly deep Windows provenance and ACL handling. Your original commit and authorship are preserved as the first commit in that PR.

The key Windows mental model is:

  1. File trust and package trust answer different questions.
  2. FileSignatureInfo tells us about the exact file or its catalog.
  3. Get-AppxPackage tells us that Windows trusts an installed package identity.
  4. Proving that the package is installed does not automatically prove that an arbitrary file named wslrelay.exe belongs to it.
  5. At a credential boundary, we need an unbroken chain from listener, to process, to executable path, to package ownership.

The original fallback established package identity, publisher, and signature kind, but the inspected relay path was not passed into that decision. That meant a genuine WSL package could be installed while a different relay under the broad canonical-path rule inherited the package's trust.

The maintainer patch keeps your primary design and adds the missing binding:

  • File-level Authenticode remains first.
  • Fallback remains limited to wslrelay.exe.
  • A WindowsApps relay must be beneath the exact install location reported for the genuine WSL package.
  • A sibling WindowsApps package is rejected.
  • Reparse points are rejected through the protected path ancestry.
  • The external C:\Program Files\WSL\wslrelay.exe layout must match exactly.
  • External path ownership and effective write ACLs are restricted to SYSTEM, Administrators, and TrustedInstaller.
  • The external relay file version must match the installed WSL package version.
  • Missing or ambiguous evidence fails closed.

There were also two subtle Windows ACL details worth calling out:

  • An inherit-only CREATOR OWNER ACE describes rights that may be materialized on descendants. It does not grant those rights on the current directory.
  • A null DACL and an empty DACL are opposites. A null DACL grants everyone full access; an empty DACL denies access. High-level rule enumeration can look empty in both cases, so security code must inspect the raw descriptor.

We also changed the tests so the primary Authenticode outcome is injected. On the maintainer host, WSL 2.9.4's external relay is already validly Microsoft-signed. Without injection, tests intended for package fallback can accidentally pass through the primary path and never test the fallback.

#1201 includes the full history, threat model, implementation walkthrough, validation counts, current-head live package/ACL/version proof, and the proof limitation. The final structured security review is clean.

Closing this PR as superseded by #1201. Thank you again for surfacing the compatibility issue and for providing the initial implementation that the maintainer patch builds on.

@shanselman shanselman closed this Aug 21, 2026
@shanselman shanselman removed the status: 🚢 actively landing A maintainer or agent is actively driving this item through implementation, validation, or merge. label Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. P0 Emergency: data loss, security bypass, crash loop, or unusable core runtime. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants