Skip to content

fix(configure): mask gateway token input in CLI wizard prompt#91059

Merged
vincentkoc merged 3 commits into
openclaw:mainfrom
anurag-bg-neu:fix/gateway-token-cleartext
Jun 13, 2026
Merged

fix(configure): mask gateway token input in CLI wizard prompt#91059
vincentkoc merged 3 commits into
openclaw:mainfrom
anurag-bg-neu:fix/gateway-token-cleartext

Conversation

@anurag-bg-neu

@anurag-bg-neu anurag-bg-neu commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

What problem does this PR solve?
The openclaw configure --section gateway wizard presents a Gateway token (blank to generate) prompt using clack text(), which echoes every typed character — and the auto-generated token — in cleartext on the terminal. Anyone running the wizard over a shared screen, screen recording, or pair-programming session can see the token.

Why does this matter now?
This is the same class of UX/security defect fixed in #76693 (onboarding wizard) and #90571 (gateway password prompt). The Gateway token prompt was the one remaining unmasked credential surface in the configure --section gateway flow.

What is the intended outcome?
The Gateway token (blank to generate) prompt renders bullets (••••) instead of typed or auto-generated characters. The persisted value in openclaw.json is the actual token string — masking is render-only, config behavior is unchanged.

What is intentionally out of scope?

What does success look like?
Running the published-CLI repro after this patch shows bullets where the before screenshots show cleartext. The openclaw.json gateway.auth.token field holds the actual token string, not bullet characters.

What should reviewers focus on?

  • That the new password helper in configure.shared.ts matches the pattern of the existing text/confirm/select wrappers.
  • That the passwordInput local-variable rename in the authMode === "password" branch avoids shadowing the newly imported password helper (same rename PR fix(configure): mask gateway password input in CLI wizard prompt #90571 applies — both PRs are in-flight).
  • That configure.gateway.test.ts's existing textQueue fixtures drive the token branch via the new password mock without any fixture changes.

Linked context

Which issue does this close?

None — this PR was authored from an audit of unmasked credential prompts, not in response to an open issue.

Which issues, PRs, or discussions are related?

Was this requested by a maintainer or owner?

No — found while auditing remaining unmasked credential prompts after #76693 merged.

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: openclaw configure --section gateway echoes the Gateway token in cleartext — both typed tokens and the auto-generated hex token are visible on-screen.
  • Real environment tested: Windows 10 Home Single Language (build 19045.7291), PowerShell, native window. Published CLI for before-evidence: OpenClaw 2026.6.1 (2e08f0f) (installed via documented global installer). Local dev for after-evidence: OpenClaw 2026.6.2 (079414a) from this branch via pnpm openclaw configure --section gateway.
  • Exact steps or command run after this patch:
    1. git checkout fix/gateway-token-cleartext
    2. pnpm install && pnpm build
    3. pnpm openclaw configure --section gateway
    4. Choose: bind = Loopback, access protection = Token, Tailscale = Off
    5. At Gateway token (blank to generate) — type any string or press Enter; observe bullets ••••
  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):
repro_a_fix_gateway_token_1 repro_a_fix_gateway_token_2 repro_a_fix_gateway_token_3 repro_a_fix_gateway_token_4
  • Observed result after fix: Characters at the Gateway token (blank to generate) prompt render as ••••••••••. The gateway.auth.token value in openclaw.json is the actual token string (not bullets), confirming masking is render-only and config persistence is unaffected.
  • What was not tested: macOS, Linux. The change touches cross-platform @clack/prompts code with no process.platform branching — the fix applies on all three platforms automatically. Verification on each is tracked as a separate atomic task — macOS: [verify] gateway token mask renders bullets on macOS (PR #91059) #91064; Linux: [verify] gateway token mask renders bullets on Linux (PR #91059) #91065.
  • Proof limitations or environment constraints: My machine is Windows-only. I cannot personally screenshot macOS/Linux output.
  • Before evidence (optional but encouraged):
repro_a_issue_gateway_token_2 repro_a_issue_gateway_token_1

Tests and validation

Which commands did you run?

pnpm build ; pnpm check ; pnpm test

pnpm tsgo:core run after each file edit — green each time. pnpm test:changed — one pre-existing failure in src/crestodian/operations.test.ts (Windows POSIX-path hardcode /tmp/work vs E:\tmp\work) — not caused by this diff, per CONTRIBUTING.md:128-129. Full build green (all phases: tsdown, ui:build, runtime-postbuild). pnpm check — typecheck green; no-shadow lint error on password resolved in this PR by renaming const password → const passwordInput in the authMode === "password" branch; pre-existing unrelated lint errors in extensions/device-pair/ and scripts/ not addressed per CONTRIBUTING.md:128-129. After fix commit fc5f145c0e: pnpm build ✓; pnpm check typecheck ✓ (4 pre-existing lint failures in extensions/device-pair/notify.ts + scripts/ — unrelated); pnpm test:changed — 47/48 pass (1 pre-existing POSIX-path failure in crestodian/operations.test.ts, unrelated).

What regression coverage was added or updated?

Added password: vi.fn() mock to configure.gateway.test.ts, wired through the existing textQueue so all 11 tests continue to pass via the new mock path with no fixture changes. Added clackPassword: vi.fn() and password: mocks.clackPassword to the @clack/prompts mock in src/commands/configure.wizard.test.ts so the shared module import chain resolves correctly (commit fc5f145c0e).

What failed before this fix, if known?

No automated test failure — this is a TTY rendering defect not assertable by unit tests. The proof is the live terminal capture.

If no test was added, why not?

Automated tests cannot assert "the TTY renders bullets, not characters." The structural fix (swapping text → password) is verified by the manual repro screenshots and by the mock wiring that confirms the prompt feeds the same config persistence path.

Risk checklist

Did user-visible behavior change? (Yes/No)

Yes — the Gateway token (blank to generate) prompt now renders bullets instead of characters. The initialValue pre-fill (which displayed the auto-generated token in the field before the user pressed Enter) is also removed, as @clack/prompts password() does not accept initialValue. The blank-input fallback (normalizeGatewayTokenInput(tokenInput) || randomToken()) still auto-generates a token when the field is left blank.

Did config, environment, or migration behavior change? (Yes/No)

No — gateway.auth.token in openclaw.json is persisted as the typed or auto-generated string, unchanged. No migration needed.

Did security, auth, secrets, network, or tool execution behavior change? (Yes/No)

Yes — masking the on-screen rendering of token input. This is the intended security fix; no other auth/network behavior is altered.

What is the highest-risk area?

Dropping initialValue: randomToken() changes the UX: the field no longer pre-fills with a generated token. Users who pressed Enter to accept the default will still get a generated token, but it won't be visible during entry. This is intentional — showing it would defeat the masking.

How is that risk mitigated?

The "blank to generate" message communicates that blank input is valid. The generated token is stored in openclaw.json immediately after the wizard completes and is readable there. This is consistent with how all other credential prompts in the wizard behave after the #76693/#90571/#90893 series of fixes.

Current review state

What is the next action?

Maintainer review.

What is still waiting on author, maintainer, CI, or external proof?

Which bot or reviewer comments were addressed?

ClawSweeper Codex review (2026-06-07, commit 079414a9): P1 finding addressed in commit fc5f145c0e — added clackPassword: vi.fn() to the vi.hoisted() mocks and password: mocks.clackPassword to the vi.mock("@clack/prompts", ...) block in src/commands/configure.wizard.test.ts. Mirrors the sibling fix in PR #90571 (commit fa3f5e8aa4). Gate: pnpm build ✓; pnpm check typecheck ✓ (pre-existing lint failures in extensions/device-pair/ and scripts/ — unrelated); pnpm test:changed — 47/48 pass (1 pre-existing Windows POSIX-path failure in crestodian/operations.test.ts).


AI-assisted PR:

  • Mark as AI-assisted in the PR title or description
  • Include human-run real behavior proof from your own setup. AI-generated tests, mocks, lint, typechecks, and CI output are supplemental only; they do not prove the fix works for users.
  • Include prompts or session logs if possible (super helpful!)
  • Confirm you understand what the code does
  • If you have access to Codex, run codex review --base origin/main locally and address the findings before asking for review
  • Resolve or reply to bot review conversations after you address them

@openclaw-barnacle openclaw-barnacle Bot added commands Command implementations size: XS triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 7, 2026
@clawsweeper

clawsweeper Bot commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed June 13, 2026, 7:28 PM ET / 23:28 UTC.

Summary
The PR changes openclaw configure --section gateway token and password prompts to use the shared masked password wrapper and updates Vitest mocks/assertions for those prompt calls.

PR surface: Source +6, Tests +14. Total +20 across 4 files.

Reproducibility: yes. Current main source routes the affected configure gateway token and password prompts through text(), and inspected before/after screenshots show the token prompt changing from cleartext to bullets; I did not run the interactive TTY flow locally.

Review metrics: 1 noteworthy metric.

  • Credential prompt surfaces: 2 changed. The branch now masks both configure gateway token and gateway password prompts, which matters because the original PR body still describes the password prompt as out of scope.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

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

Rank-up moves:

  • Update the PR body or maintainer notes so the current branch scope says it masks both gateway token and gateway password prompts.

Risk before merge

  • [P1] The latest force-push expands this branch to gateway password masking too, so maintainers should reconcile fix(configure): mask gateway password input in CLI wizard prompt #90571 or update this PR body before landing to avoid two open PRs racing the same prompt.
  • [P1] The attached real terminal screenshots are Windows-only for this exact PR; the code path is platform-neutral @clack/prompts, and macOS/Linux verification remains tracked in linked follow-up issues.

Maintainer options:

  1. Decide the mitigation before merge
    Land one focused configure-gateway secret-prompt fix that masks both plaintext token and password input while preserving the actual stored secret values, then close or rebase the sibling password PR.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • No ClawSweeper repair lane is needed; the remaining action is maintainer review and sibling PR reconciliation, not a narrow automated code repair.

Security
Cleared: The diff reduces terminal exposure of gateway credentials and does not add dependencies, workflow changes, install scripts, or broader secret-handling paths.

Review details

Best possible solution:

Land one focused configure-gateway secret-prompt fix that masks both plaintext token and password input while preserving the actual stored secret values, then close or rebase the sibling password PR.

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

Yes. Current main source routes the affected configure gateway token and password prompts through text(), and inspected before/after screenshots show the token prompt changing from cleartext to bullets; I did not run the interactive TTY flow locally.

Is this the best way to solve the issue?

Yes. The PR uses the existing Clack password prompt at the configure command boundary, keeps normalization and config persistence unchanged, and avoids adding a new config or migration path.

AGENTS.md: found and applied where relevant.

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

Label changes

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. Inspected screenshots show the after-fix gateway token prompt rendering bullets and the config retaining the real token; the broadened password change is supported by the same masked helper path and sibling screenshot proof.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • remove rating: 🦞 diamond lobster: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.

Label justifications:

  • P2: This is a normal-priority CLI credential exposure hardening fix with limited blast radius to the configure gateway wizard.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (screenshot): Inspected screenshots show the after-fix gateway token prompt rendering bullets and the config retaining the real token; the broadened password change is supported by the same masked helper path and sibling screenshot proof.
  • proof: sufficient: Contributor real behavior proof is sufficient. Inspected screenshots show the after-fix gateway token prompt rendering bullets and the config retaining the real token; the broadened password change is supported by the same masked helper path and sibling screenshot proof.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. Inspected screenshots show the after-fix gateway token prompt rendering bullets and the config retaining the real token; the broadened password change is supported by the same masked helper path and sibling screenshot proof.
Evidence reviewed

PR surface:

Source +6, Tests +14. Total +20 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 2 12 6 +6
Tests 2 14 0 +14
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 26 6 +20

What I checked:

  • Root policy read: Read the full root AGENTS.md and applied its deep-review, dependency-contract, config/setup compatibility, and security-review guidance; no scoped AGENTS.md exists under src/commands. (AGENTS.md:1, 47759c35063c)
  • Current main cleartext prompt source: Current main calls the shared text prompt for Gateway token (blank to generate) with initialValue: randomToken(), and also calls text for Gateway password. (src/commands/configure.gateway.ts:235, 47759c35063c)
  • PR head masked prompt source: At PR head, both plaintext gateway token input and gateway password input call the shared password wrapper; token normalization and generated fallback still feed gatewayToken as before. (src/commands/configure.gateway.ts:236, 0f5a9ac38d2f)
  • Shared wrapper source: The PR adds a password wrapper in configure.shared.ts that imports clackPassword and applies the same styled-message wrapping pattern as text, confirm, and select. (src/commands/configure.shared.ts:108, 0f5a9ac38d2f)
  • Regression coverage source: The PR head mocks the shared password wrapper and asserts the token and password branches call it with the expected messages and password validation function. (src/commands/configure.gateway.test.ts:121, 0f5a9ac38d2f)
  • Dependency contract proof: @clack/[email protected] defines password(opts) with message, optional mask, validate, and clearOnError; the package docs/type surface do not include initialValue for password prompts, matching the PR's removal of the visible generated token prefill. (pnpm-lock.yaml:2353, 47759c35063c)

Likely related people:

  • vincentkoc: Current main blame for the configure gateway prompt block and the latest PR commit both point to recent work by Vincent Koc on this exact file and prompt surface. (role: recent area contributor; confidence: high; commits: eb1b640854bb, 0f5a9ac38d2f; files: src/commands/configure.gateway.ts, src/commands/configure.gateway.test.ts)
  • steipete: Recent history shows configure wizard helper documentation and related source touches across configure.gateway.ts and configure.shared.ts. (role: recent configure wizard contributor; confidence: medium; commits: 118060157d21; files: src/commands/configure.gateway.ts, src/commands/configure.shared.ts, src/commands/configure.wizard.ts)
  • joshavant: The gateway SecretRef/auth-mode support commit touched configure.gateway.ts, gateway auth config, docs, and related tests around the auth branch this PR changes. (role: adjacent gateway auth contributor; confidence: medium; commits: 72cf9253fcb5; files: src/commands/configure.gateway.ts, src/commands/configure.gateway-auth.ts, src/config/types.gateway.ts)
  • anurag-bg-neu: Beyond opening this PR, this contributor authored the merged onboarding credential-masking work that established the same masked prompt pattern used here. (role: credential-masking feature contributor; confidence: medium; commits: a3db64c265e6, 7f81d8543d14, 46d5ca306247; files: src/wizard/clack-prompter.ts, src/wizard/setup.gateway-config.ts, src/commands/configure.gateway.ts)
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 backlog priority with limited blast radius. labels Jun 7, 2026
@anurag-bg-neu
anurag-bg-neu marked this pull request as ready for review June 7, 2026 01:59
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed 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 Jun 7, 2026
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 7, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 7, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 automation 🚨 May affect CI, automerge, proof capture, label sync, or maintainer automation. labels Jun 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 7, 2026
@vincentkoc vincentkoc self-assigned this Jun 13, 2026
@vincentkoc
vincentkoc force-pushed the fix/gateway-token-cleartext branch from fc5f145 to 0f5a9ac Compare June 13, 2026 23:22
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 13, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. and removed rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. labels Jun 13, 2026

@anurag-bg-neu anurag-bg-neu left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Thank you @vincentkoc for adding in the configure gateway password code checks! 👍🏼 💯
Feel free to close this PR which has the redundant checks for gateway password checks #90571

@vincentkoc

Copy link
Copy Markdown
Member

Maintainer verification for current head 0f5a9ac38d2f5d6296e55bb0a460428db8b8580a:

  • Rebased on current origin/main before review.
  • Verified the blank-token generation path remains intact while gateway token and password entry now use masked prompts.
  • Focused proof: node scripts/run-vitest.mjs src/commands/configure.gateway.test.ts src/commands/configure.wizard.test.ts — passed, 24 tests.
  • Autoreview: .agents/skills/autoreview/scripts/autoreview --mode branch --base origin/main --thinking high — clean after the prompt-sibling fix.
  • GitHub checks: current head is clean.

Merging by squash.

@vincentkoc
vincentkoc merged commit 382db15 into openclaw:main Jun 13, 2026
181 of 186 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

commands Command implementations P2 Normal backlog priority with limited blast radius. proof: 📸 screenshot Contributor real behavior proof includes screenshot evidence. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: XS status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants