fix(onboarding): mask token/credential inputs in CLI wizard prompts#76693
Conversation
|
Codex review: passed. Summary Reproducibility: yes. Source inspection shows current main routes onboarding credential entry through visible Clack Next step before merge Security Review detailsBest possible solution: Merge this Node-side masking patch through the exact-head automerge gates and keep #76698 open for the macOS CLI no-echo reader. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main routes onboarding credential entry through visible Clack Is this the best way to solve the issue? Yes after the maintainer split decision. The What I checked:
Likely related people:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 0e4d28aa9e65. |
|
Maintainer note: OK to merge this Node-side fix. Keep #76698 open for the macOS CLI follow-up. |
|
/clawsweeper automerge |
|
🦞🦞 Source: What merged:
Automerge notes:
The automerge loop is complete. Automerge progress:
|
…penclaw#76693) Summary: - The PR adds `sensitive` support to wizard text prompts, routes sensitive Clack prompts through `password()`, ... preserves existing gateway secrets through masked-preview confirms, and adds tests plus a changelog entry. - Reproducibility: yes. Source inspection shows current main routes onboarding credential entry through visibl ... y provides a concrete Windows PowerShell `openclaw onboard --install-daemon` reproduction with screenshots. Automerge notes: - No ClawSweeper repair was needed after automerge opt-in. Validation: - ClawSweeper review passed for head a3db64c. - Required merge gates passed before the squash merge. Prepared head SHA: a3db64c Review: openclaw#76693 (comment) Co-authored-by: anurag-bg-neu <bheemappagnanamurt.a@northeastern.edu>
…penclaw#76693) Summary: - The PR adds `sensitive` support to wizard text prompts, routes sensitive Clack prompts through `password()`, ... preserves existing gateway secrets through masked-preview confirms, and adds tests plus a changelog entry. - Reproducibility: yes. Source inspection shows current main routes onboarding credential entry through visibl ... y provides a concrete Windows PowerShell `openclaw onboard --install-daemon` reproduction with screenshots. Automerge notes: - No ClawSweeper repair was needed after automerge opt-in. Validation: - ClawSweeper review passed for head a3db64c. - Required merge gates passed before the squash merge. Prepared head SHA: a3db64c Review: openclaw#76693 (comment) Co-authored-by: anurag-bg-neu <bheemappagnanamurt.a@northeastern.edu>
Summary
openclaw onboardwizard were echoed in cleartext into the terminal — leaving secrets in PowerShell scrollback,Start-Transcriptlogs, screenshots, and screen-shares. Reproduced on Windows PowerShell during a normalopenclaw onboard --install-daemonsession.gh auth login,npm login,aws configure,gcloud authall mask this for the same reason.sensitive?: booleantoWizardTextParams; clack frontend dispatches to@clack/prompts.password()when set;sensitive: trueflipped at every onboarding credential prompt across the Node CLI; existing tokens/passwords preserved via aconfirmwithmaskApiKey()masked-preview before the masked text prompt.openclaw-mac wizardsession-client masking is deliberately deferred → tracked at macOSopenclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698 (see "Out-of-scope leak path" in Security Impact for rationale and maintainer-decision options).Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
openclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698 (macOS CLI follow-up tracking)openclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698)Root Cause
WizardTextParamsdid not expose asensitiveflag, so the clack prompter always calledtext()regardless of whether the prompt was asking for a credential. Every wizard text prompt — including credential entry — rendered cleartext that persisted in the terminal stream. TheWizardSteptype already had asensitive?: booleanfield (sketched but unwired), so the design intent was there; this PR completes the Node-side plumbing.sensitiveflag propagates from caller through the wizard step contract. Adding session-level + call-site assertions.Regression Test Plan
src/wizard/session.test.ts→ forwards sensitive flag to the emitted text stepsrc/wizard/setup.gateway-config.test.ts→ keeps OPENCLAW_GATEWAY_TOKEN in advanced flow when user confirms keeping existingsrc/commands/onboard-remote.test.ts→ keeps an existing remote gateway token / password when user confirms via masked-preview promptsrc/commands/onboard-search.test.ts→ tightened Gemini-key assertion now requiressensitive: trueon the prompt stepsensitiveflag is the contract between wizard runner and rendering frontend. If it stops propagating, masking silently regresses everywhere downstream. Asserting at the contract level catches that without needing TTY-mocked clack.User-visible / Behavior Changes
Credential prompts in
openclaw onboard(andopenclaw onboard --remote) now render as masked-bullet input. Entered values are no longer echoed into the terminal:--remoteonboarding)Enter <SKILL_ENV_VAR>(skill credential entry)When an existing credential is detected (env var or saved config), users are asked via a
confirmstep with amaskApiKey()masked preview ("Use existing gateway token (env-…oken)?") before the masked text prompt — preserves "press Enter to keep current" without rendering the secret.No config-shape changes; non-interactive onboarding paths bypass the prompter entirely and are unchanged.
Diagram
Security Impact (required)
Start-Transcriptlogs, screenshots, recordings). Storage / transmission / logging paths after submission are untouched.sensitivecode path is unchanged for every existing caller. The masked path uses@clack/prompts.password()— same library, same major version (^1.2.0) the project already depends on. Tests assert the dispatch andWizardStep.sensitivepropagation.@openclaw/secopsownership globs (/src/secrets/,/src/security/,/src/agents/**/*auth*.ts,/src/gateway/**/*auth*.ts). Maintainers welcome to route to secops anyway as a courtesy security review.Out-of-scope leak path (acknowledged, tracked at #76698)
The bundled
openclaw-mac wizardCLI inapps/macos/Sources/OpenClawMacCLI/WizardCommand.swift:445still reads every text step with an echoingreadLine()and displays the bracketed[initial]value, regardless ofstep.sensitive. That's a real residual leak for users on the macOS session-client surface (the SwiftUI app atapps/macos/Sources/OpenClaw/OnboardingWizard.swift:303already honorssensitiveviaSecureField).Not fixed in this PR because (a) authored on Windows with no Apple toolchain to run
swift build/swiftlint/swiftformat --lint, (b) prior speculative iterations on #76615 kept failing macos-swift CI. Staying TDD-strict means I don't keep guessing.Maintainer decision needed: please choose one —
openclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698: defer merge until a macOS-toolchain contributor lands macOSopenclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698, then merge both together. Closes the leak completely before any release.openclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698 progress independently. Documents the residual macOS-CLI surface so users runningopenclaw-mac wizardknow to use env vars until macOSopenclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698 lands.Either is fine by me — the deferral just needs to be explicit and tracked, not silent.
Repro + Verification
Environment
provider-auth-input.tsandsearch-setup.ts)Steps
pnpm openclaw onboard --install-daemon(builds-on-the-fly viascripts/run-node.mjs).AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXX).Start-Transcriptbefore step 1.Expected
••••...while typing/pasting.Start-Transcriptlog do not contain the cleartext.Actual (this PR)
@clack/prompts.password(); cleartext never placed into the terminal stream.Evidence
Before masking the token
After masking the token
The "after" screenshot shows:
••••...)maskApiKey()head/tail safe preview format (AIza…WsDI)Human Verification (required)
What was personally verified:
a3db64c265):pnpm check:test-types— clean locally (this lane was red on the prior PR's CI at SHAdcfca89199; passes now that the Swift change is reverted to upstream)pnpm tsgo:core— cleanpnpm check— 0 warnings, 0 errors across all 3 oxlint lanes plus all policy guardssetup.gateway-config.test.ts— 11/11 (10 prior + 1 new)session.test.ts— 6/6 (5 upstream + 1 new)onboard-remote.test.ts— 12/12 (10 prior + 2 new)onboard-search.test.ts— 15/15 (tightened existing assertion)openclaw-mac wizardsession-client masking → see "Out-of-scope leak path" above. Tracked at macOSopenclaw-mac wizardCLI: honorstep.sensitivefor credential text prompts #76698.Review Conversations
Compatibility / Migration
sensitiveis an optional field; all existing callers (and any third-party plugin code consumingWizardPrompter) continue to work unchanged.Risks and Mitigations
password()does not acceptinitialValue/placeholder, sosensitive: truetext prompts ignore those twoWizardTextParamsfields.initialValue(setup.gateway-config.ts:212,onboard-remote.ts:198, 230) now branch through aprompter.confirmwithmaskApiKey()masked preview before falling through to the masked text prompt. Preserves the "press Enter to keep current" UX without rendering the secret.AI assist disclosure (per CONTRIBUTING.md)
claude-opus-4-7) via Claude Code. I reviewed every change before commit.swift builddeliberately not in scope here — see Out-of-scope leak path above.