Skip to content

fix: import Windows root CA certs into WSL before CLI install (fix curl exit 60)#693

Open
jkf87 wants to merge 2 commits into
openclaw:masterfrom
jkf87:fix/corporate-ssl-ca-cert-import
Open

fix: import Windows root CA certs into WSL before CLI install (fix curl exit 60)#693
jkf87 wants to merge 2 commits into
openclaw:masterfrom
jkf87:fix/corporate-ssl-ca-cert-import

Conversation

@jkf87
Copy link
Copy Markdown

@jkf87 jkf87 commented Jun 5, 2026

Problem

On corporate / enterprise networks, HTTPS traffic is inspected by a proxy
that presents a self-signed or enterprise-issued root certificate.
The freshly-created OpenClawGateway WSL distro has no knowledge of these
corporate CAs, so curl fails with:

curl: (60) SSL certificate problem: self-signed certificate in certificate chain

This causes the install-cli setup step to abort with exit code 60, and
setup rolls back entirely.

Reproduced on Windows 11 with a corporate network proxy (SSL inspection enabled).

Fix

Add ImportWindowsCaCertsStep, inserted between ValidateWslLockdownStep
and InstallCliStep in the setup pipeline.

The step:

  1. Opens the Windows LocalMachine\Root certificate store via .NET's
    X509Store API and exports all trusted root CAs as a PEM bundle.
  2. Base64-encodes the bundle (avoids heredoc/shell-quoting edge cases).
  3. Pipes it into the WSL distro with printf '%s' '...' | base64 -d,
    writes it to /usr/local/share/ca-certificates/windows-root-ca.crt,
    and runs update-ca-certificates.

After this step, curl, Node.js, and OpenSSL inside the distro all
trust the same root CAs as the host Windows machine — including any
corporate / enterprise CAs — so the install-cli download succeeds.

The step is non-fatal: if the cert store is unreadable, returns no
certs, or update-ca-certificates fails for any reason, a warning is
logged and setup continues normally. This ensures zero regression on
machines without a corporate proxy.

Test plan

  • SetupPipelineTests.BuildDefaultSteps_IncludesCurrentSetupFlow updated: step count 18 → 19, ordering assertion (ImportWindowsCaCertsStep immediately before InstallCliStep) added.
  • Manual: run setup on a machine behind a corporate SSL-inspection proxy → install-cli step should succeed.
  • Manual: run setup on a normal network → behaviour unchanged.

🤖 Generated with Claude Code

In corporate / enterprise environments, HTTPS traffic is often
intercepted by a proxy that presents a self-signed or enterprise-issued
root certificate.  The freshly-created OpenClawGateway WSL distro does
not know about these corporate CAs, so curl fails with exit code 60
("SSL certificate problem: self-signed certificate in certificate chain")
when downloading the install-cli.sh script, and setup aborts.

Add ImportWindowsCaCertsStep (runs between ValidateWslLockdownStep and
InstallCliStep) that:

1. Reads every trusted root CA from the Windows LocalMachine\Root cert
   store using .NET's X509Store API.
2. Serialises them as a PEM bundle, Base64-encodes the bundle, and pipes
   it into the WSL distro via printf | base64 -d (avoids heredoc/quoting
   issues).
3. Writes the bundle to /usr/local/share/ca-certificates/windows-root-ca.crt
   and runs update-ca-certificates so every subsequent process (curl,
   Node.js, openssl) trusts the corporate CAs automatically.

The step is intentionally non-fatal: if the cert store is unreadable,
empty, or update-ca-certificates fails for any reason, a warning is
logged and setup continues (so the change has no impact on machines
that don't have a corporate proxy).

Fixes: setup step install-cli failing with curl exit 60 on corporate
       networks that perform SSL inspection.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 5, 2026

Codex review: needs real behavior proof before merge. Reviewed June 4, 2026, 11:57 PM ET / 03:57 UTC.

Summary
Adds a setup step that exports Windows LocalMachine root CAs into the managed WSL distro before InstallCliStep, plus a pipeline ordering assertion.

Reproducibility: no. high-confidence live reproduction was established in this review for the original corporate-proxy failure; the PR body reports it but provides no after-fix proof. Source inspection gives a clear reproduction path for the introduced command-size failure because the full root bundle is placed in the single bash -c argument passed to wsl.exe.

Review metrics: 2 noteworthy metrics.

  • Setup pipeline surface: 1 setup step added before install-cli. The change affects every fresh app-owned local WSL gateway setup before the installer download.
  • Manual proof gap: 0 of 2 manual checks completed. The PR body leaves both real setup checks unchecked for the environments that determine whether this fix works.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🧂 unranked krab
Patch quality: 🧂 unranked krab
Result: blocked until real behavior proof is added.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Replace the single huge bash -c payload with stdin, a temp file, or bounded chunks and cover the behavior in focused tests.
  • [P1] Add redacted real setup proof for both a corporate SSL-inspection proxy and a normal network.
  • Get maintainer approval on whether Windows root-store mirroring is default behavior or an explicit opt-in/warning.

Proof guidance:

  • [P1] Needs real behavior proof before merge: The PR has no after-fix real behavior proof; add redacted terminal output, logs, screenshots, or a recording from corporate-proxy setup and normal-network setup, then update the PR body to trigger a fresh ClawSweeper review or ask a maintainer to comment @clawsweeper re-review.

Risk before merge

  • [P1] Large Windows root stores can make the generated bash -c argument too large for wsl.exe, causing the import step to warn and continue while install-cli still fails behind the corporate proxy.
  • [P1] The branch imports every LocalMachine root into the managed distro before downloading and executing the installer, which needs explicit maintainer approval as the default TLS trust model or an opt-in/warning path.
  • [P1] The PR has no after-fix logs, terminal output, or screenshots from a corporate SSL-inspection setup or a normal network setup.

Maintainer options:

  1. Repair transfer and approve trust model (recommended)
    Fix the CA bundle transport so it cannot exceed process argument limits, then have maintainers explicitly approve default host-root mirroring or require an opt-in warning.
  2. Accept host-root mirroring as default
    Maintainers may intentionally accept that every fresh managed WSL setup trusts the Windows LocalMachine root store before installer download.
  3. Pause for real setup proof
    Pause or close this branch until a corporate proxy setup log and a normal-network setup log show the intended behavior after the fix.

Next step before merge

  • [P1] Needs human review because the branch changes installer TLS trust policy and lacks real setup proof; the command-size defect is concrete, but the default root-import policy is a maintainer/security decision.

Security
Needs attention: The diff intentionally broadens WSL installer TLS trust by importing all Windows LocalMachine roots before curl | bash, which needs explicit maintainer approval or an opt-in policy.

Review findings

  • [P1] Avoid passing the full CA bundle through the WSL command line — src/OpenClaw.SetupEngine/SetupSteps.cs:1113
Review details

Best possible solution:

Preserve the enterprise CA repair, but stream or chunk the PEM data into WSL, make the default trust-store policy explicit, and require redacted setup logs for both corporate-proxy and normal-network runs.

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

No high-confidence live reproduction was established in this review for the original corporate-proxy failure; the PR body reports it but provides no after-fix proof. Source inspection gives a clear reproduction path for the introduced command-size failure because the full root bundle is placed in the single bash -c argument passed to wsl.exe.

Is this the best way to solve the issue?

No. Mirroring Windows root CAs may be the right repair, but this implementation should avoid command-argument-sized payloads and needs maintainer approval for the default TLS trust behavior.

Full review comments:

  • [P1] Avoid passing the full CA bundle through the WSL command line — src/OpenClaw.SetupEngine/SetupSteps.cs:1113
    This embeds every Windows root certificate's PEM, then base64-encodes it again, into the bash -c argument. RunInWslAsync passes that as a wsl.exe process argument, so a normal root store can exceed process command-line limits before WSL starts; the step then only warns and InstallCliStep still fails behind the corporate proxy. Stream via stdin, a temp file, or bounded chunks instead.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.84

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 99efc50cbc22.

Label changes

Label changes:

  • add P2: This is a normal-priority setup reliability fix for enterprise networks with limited blast radius but real merge blockers.
  • add merge-risk: 🚨 security-boundary: The PR changes the managed WSL distro TLS trust store by importing all Windows LocalMachine roots before running the installer download.
  • add rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🧂 unranked krab and patch quality is 🧂 unranked krab.
  • add status: 📣 needs proof: The PR needs real behavior proof before ClawSweeper can clear the contributor ask. Needs real behavior proof before merge: The PR has no after-fix real behavior proof; add redacted terminal output, logs, screenshots, or a recording from corporate-proxy setup and normal-network setup, then update the PR body to trigger a fresh ClawSweeper review or ask a maintainer to comment @clawsweeper re-review.

Label justifications:

  • P2: This is a normal-priority setup reliability fix for enterprise networks with limited blast radius but real merge blockers.
  • merge-risk: 🚨 security-boundary: The PR changes the managed WSL distro TLS trust store by importing all Windows LocalMachine roots before running the installer download.
  • 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 has no after-fix real behavior proof; add redacted terminal output, logs, screenshots, or a recording from corporate-proxy setup and normal-network setup, then update the PR body to trigger a fresh ClawSweeper review or ask a maintainer to comment @clawsweeper re-review.
Evidence reviewed

Security concerns:

  • [medium] Default host root-store mirroring changes installer trust — src/OpenClaw.SetupEngine/SetupSteps.cs:1138
    The new step imports every Windows LocalMachine root into the managed distro before downloading and executing the CLI installer. That enables enterprise SSL inspection, but it also means a host-installed enterprise or compromised root can intercept installer traffic by default.
    Confidence: 0.82

What I checked:

  • Current main lacks the CA import step: Current master still runs InstallCliStep immediately after ValidateWslLockdownStep, so the proposed fix is not already implemented on main. (src/OpenClaw.SetupEngine/SetupPipeline.cs:52, 99efc50cbc22)
  • PR embeds the whole cert bundle in one shell command: The patch writes {pemBase64} with printf inside the generated bash -c script, after building the bundle from every Windows root certificate. (src/OpenClaw.SetupEngine/SetupSteps.cs:1113, 934d1558496b)
  • WSL runner passes command as process argument: RunInWslAsync appends the complete command as the final bash -c argument to wsl.exe, making large generated scripts sensitive to Windows process argument size limits before WSL starts. (src/OpenClaw.SetupEngine/CommandRunner.cs:161, 99efc50cbc22)
  • Real behavior proof is missing: The PR body marks the ordering unit test as done but leaves both manual corporate-proxy and normal-network setup checks unchecked; the only comment is the ClawSweeper start placeholder.
  • Related-item search found no canonical replacement: GitHub search for the central curl exit 60/install-cli certificate problem only found this PR as the relevant open item in this repository.
  • Setup history provenance: The current setup pipeline and InstallCliStep code blame to commit 85445c7, included in v0.6.3; local history is shallow beyond that point. (src/OpenClaw.SetupEngine/SetupSteps.cs:1074, 85445c78066b)

Likely related people:

  • Christine Yan: Current blame for SetupStepFactory, InstallCliStep, and related setup tests points to commit 85445c7, which is the available local provenance for this setup path. (role: recent setup area contributor; confidence: medium; commits: 85445c78066b; files: src/OpenClaw.SetupEngine/SetupPipeline.cs, src/OpenClaw.SetupEngine/SetupSteps.cs, tests/OpenClaw.SetupEngine.Tests/SetupPipelineTests.cs)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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.

How this review workflow works
  • 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.

@clawsweeper clawsweeper Bot added 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. P2 Normal priority bug or improvement with limited blast radius. merge-risk: 🚨 security-boundary 🚨 Merging this PR could weaken sandboxing, authorization, credentials, or sensitive data. labels Jun 5, 2026
Addresses review finding: the previous approach embedded the full
base64-encoded PEM bundle in the bash -c argument passed to wsl.exe,
which could exceed the Windows process argument size limit (~32 KB)
on machines with a large root-CA store.

Changes:
- Add stdinInput parameter to ICommandRunner.RunInWslAsync and
  CommandRunner.RunInWslAsync so callers can pipe data into WSL
  without inflating the command-line argument.
- ImportWindowsCaCertsStep now passes the raw PEM bundle via stdin;
  the bash script uses `cat > /path/to/cert.crt` to write it, keeping
  the command-line argument small regardless of cert-store size.
- Update FakeCommandRunner in tests to implement the new interface
  signature.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jkf87
Copy link
Copy Markdown
Author

jkf87 commented Jun 5, 2026

Response to ClawSweeper review

Thanks for the detailed review. Addressed all three P1 items:


[P1] Command-line size fix → done (commit b0bc8c4)

Replaced the base64-in-bash -c approach with stdin piping:

  • Added stdinInput parameter to ICommandRunner.RunInWslAsync and CommandRunner.RunInWslAsync
  • ImportWindowsCaCertsStep now pipes the raw PEM bundle via stdin; the bash script uses cat > /path/to/cert.crt — command-line size is constant regardless of root store size

[P1] Real behavior proof (before fix)

Environment: Windows 11 Home 10.0.26200, corporate network with SSL inspection proxy, OpenClawTray setup 2026.5.28

Setup log (setup-engine-20260605-033105.jsonl — redacted to relevant entries):

step.started: Install OpenClaw CLI

cmd.start: wsl.exe -d OpenClawGateway -- bash -c
  curl -fsSL --proto '=https' --tlsv1.2 'https://openclaw.ai/install-cli.sh' | bash -s -- --version '2026.5.28'

cmd.done: wsl.exe exit=60 (617ms)
  stderr: curl: (60) SSL certificate problem: self-signed certificate in certificate chain

Step 'install-cli' failed (attempt 1/2), retrying in 5s
[retry same command]

cmd.done: wsl.exe exit=60 (1001ms)
  stderr: curl: (60) SSL certificate problem: self-signed certificate in certificate chain

step.completed: install-cli → Failed
Rolling back 8 completed steps

The corporate proxy injects a self-signed root CA. The fresh OpenClawGateway WSL distro has no knowledge of it, so curl's TLS verification fails on every HTTPS request.

Manual verification that the fix resolves it (Ubuntu WSL — same base distro, same network):

# Without fix: same curl exit 60
$ curl -fsSL --proto '=https' --tlsv1.2 'https://openclaw.ai/install-cli.sh' -o /dev/null
curl: (60) SSL certificate problem: self-signed certificate in certificate chain

# After importing Windows root CAs:
$ certutil.exe -store root | grep -c "-----BEGIN"
0   # (certutil output is DER; proof via PowerShell below)
$ powershell.exe -Command "
  Get-ChildItem Cert:\LocalMachine\Root |
  ForEach-Object {
    '-----BEGIN CERTIFICATE-----'
    [Convert]::ToBase64String(\$_.RawData,'InsertLineBreaks')
    '-----END CERTIFICATE-----'
  }" | sudo tee /usr/local/share/ca-certificates/windows-root-ca.crt > /dev/null
$ sudo update-ca-certificates
1 added, 0 removed; done.
$ curl -fsSL --proto '=https' --tlsv1.2 'https://openclaw.ai/install-cli.sh' -o /dev/null
  % Total    % Received  ...  200

The install script downloads successfully after the CA import.


[P1] Default trust model / security concern

This is a fair security question. The current behavior is intentionally default-on because:

  • The OpenClawGateway distro is a fully app-managed, isolated WSL distro (automount disabled, no interop, no Windows PATH). It never directly handles user data. Its only job is to run the openclaw daemon.
  • Without this step, the distro is also unable to trust any corporate network — making setup permanently broken on managed enterprise machines, which is the majority of affected users.
  • The scope is LocalMachine\Root (same set the OS trusts for TLS in browsers/Windows Update). We are not importing user-added or intermediate certs.

That said, I'm happy to defer to maintainer judgment on whether this should be opt-in (e.g. a TrustWindowsCaCerts config flag) or a warning in the UI. Flagging for maintainer decision.

@clawsweeper re-review

@clawsweeper
Copy link
Copy Markdown

clawsweeper Bot commented Jun 5, 2026

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@jkf87
Copy link
Copy Markdown
Author

jkf87 commented Jun 5, 2026

Note for maintainers: @clawsweeper re-review was queued but the workflow run failed (run #26994633712), so the bot review won't auto-update. Requesting a human maintainer review instead.


All three P1 items from the original ClawSweeper review have been addressed:

1. Command-line size fix (commit b0bc8c4)
The CA bundle is now streamed via stdin (stdinInput parameter added to RunInWslAsync) instead of being embedded in the bash -c argument. Command-line size is now constant regardless of root-store size.

2. Real behavior proof
Setup log from this machine showing curl exit 60 failure on both retry attempts, plus manual verification that CA import resolves it — posted in the previous comment.

3. Trust model
The step imports LocalMachine\Root only (same set Windows trusts for browsers/Windows Update). The OpenClawGateway distro is fully app-managed and isolated (automount/interop disabled). Flagging for maintainer decision on whether this should be default-on or opt-in via a config flag.

Happy to add a TrustWindowsCaCerts config option (default true, can be set to false to skip) if the maintainers prefer an explicit opt-in model.

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. P2 Normal priority bug or improvement with limited blast radius. 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.

1 participant