macOS/onboarding: prompt for remote gateway auth tokens#43100
Conversation
🔒 Aisle Security AnalysisWe found 3 potential security issue(s) in this PR:
1. 🟠 SSH MITM risk: Remote gateway probe auto-trusts unknown host keys (StrictHostKeyChecking=accept-new)
Description
Vulnerable code: let options = [
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=5",
"-o", "StrictHostKeyChecking=accept-new",
"-o", "UpdateHostKeys=yes",
]RecommendationDo not automatically trust unknown SSH host keys. Recommended approaches:
Example (fail closed + app known_hosts): let knownHostsPath = "\(appSupportDir)/known_hosts"
let options = [
"-o", "BatchMode=yes",
"-o", "ConnectTimeout=5",
"-o", "StrictHostKeyChecking=yes",
"-o", "UserKnownHostsFile=\(knownHostsPath)",
// consider disabling automatic rewrite unless you have a UX for it:
"-o", "UpdateHostKeys=no",
]For first-time connections, implement a UX that:
2. 🟡 Remote gateway auth token can be persisted in plaintext config during remote probe flow
DescriptionThe new remote onboarding probe flow syncs gateway configuration to disk before probing connectivity, which can cause the gateway token to be written to a local JSON config file in plaintext. Key points:
Vulnerable flow (trigger): @MainActor
static func run() async -> RemoteGatewayProbeResult {
AppStateStore.shared.syncGatewayConfigNow()
...
}Persistence sink: @MainActor
func syncGatewayConfigNow() {
let synced = Self.syncedGatewayRoot(... remoteToken: self.remoteToken,
remoteTokenDirty: self.remoteTokenDirty)
...
OpenClawConfigFile.saveDict(synced.root)
}Impact:
RecommendationAvoid persisting the gateway token in plaintext and avoid writing it during a probe unless the user explicitly confirms saving. Suggested fixes:
Example (permission hardening after write): try data.write(to: url, options: [.atomic])
try FileManager.default.setAttributes([.posixPermissions: 0o600], ofItemAtPath: url.path)
try FileManager.default.setAttributes([.posixPermissions: 0o700],
ofItemAtPath: url.deletingLastPathComponent().path)
3. 🔵 Untrusted gateway-provided auth error message logged with OSLog privacy .public
DescriptionThe gateway's websocket
Impact:
Vulnerable code (sink): self.logger.error(
"gateway watchdog reconnect paused for non-recoverable auth failure \(error.localizedDescription, privacy: .public)"
)Source of the logged string: let msg = (res.error?["message"]?.value as? String) ?? "gateway connect failed"
throw GatewayConnectAuthError(message: msg, ...)RecommendationAvoid logging remote/server-provided messages as Recommended mitigations:
if let authError = error as? GatewayConnectAuthError {
self.logger.error(
"gateway reconnect paused for auth failure code=\(authError.detailCodeRaw ?? "unknown", privacy: .public)"
)
} else {
self.logger.error("gateway reconnect paused for auth failure")
}
let safeMsg = error.localizedDescription
.replacingOccurrences(of: "\n", with: " ")
.replacingOccurrences(of: "\r", with: " ")
self.logger.error("gateway auth failure \(safeMsg, privacy: .private)")Also consider enforcing a max length for server-provided messages before logging/surfacing them. Analyzed PR: #43100 at commit Last updated on: 2026-03-11T12:57:01Z |
Greptile SummaryThis PR adds structured remote-gateway auth error handling and contextual token-guidance UI to the macOS onboarding and Settings flows. The core change is a new
Confidence Score: 4/5
|
|
Addressed the follow-up review feedback in
Re-ran:
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: afd5e9387b
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if shouldRestoreMode { | ||
| // Reuse the shared remote endpoint stack for probing without committing the user's mode choice. | ||
| self.state.connectionMode = .remote | ||
| } |
There was a problem hiding this comment.
Avoid mutating global connection mode during probe
This probe path temporarily sets state.connectionMode to .remote even when the user has not selected Remote mode, which triggers real mode-change side effects outside onboarding. AppState.connectionMode updates are observed by the app shell (apps/macos/Sources/OpenClaw/MenuBar.swift), which calls ConnectionModeCoordinator.apply; the .remote branch in apps/macos/Sources/OpenClaw/ConnectionModeCoordinator.swift stops the local gateway and starts remote tunnel/control-channel setup. As a result, clicking Check connection from a Local/Unconfigured onboarding context can tear down the active local runtime and flap connection state despite being a read-only diagnostic.
Useful? React with 👍 / 👎.
afd5e93 to
00e2ad8
Compare
|
Landed after rebasing the PR head onto
Thanks @ngutman! |
Merged via squash. Prepared head SHA: 00e2ad8 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
Merged via squash. Prepared head SHA: 00e2ad8 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
* main: (49 commits) fix(agents): add nodes to owner-only tool policy fallbacks fix(gateway): propagate real gateway client into plugin subagent runtime fix(gateway): enforce caller-scope subsetting in device.token.rotate fix(terminal): stabilize skills table width across Terminal.app and iTerm (openclaw#42849) fix(models): guard optional model input capabilities (openclaw#42096) macOS/onboarding: prompt for remote gateway auth tokens (openclaw#43100) fix(macos): use foundationValue when serializing browser proxy POST body (openclaw#43069) feat(ios): add local beta release flow (openclaw#42991) docs(changelog): update context pruning PR reference fix(context-pruning): cover image-only tool-result pruning fix(context-pruning): prune image-containing tool results instead of skipping them (openclaw#41789) fix(agents): include azure-openai in Responses API store override (openclaw#42934) fix(telegram): fall back on ambiguous first preview sends fix(telegram): prevent duplicate messages with slow LLM providers (openclaw#41932) Providers: add Opencode Go support (openclaw#42313) fix(sandbox): sanitize Docker env before marking OPENCLAW_CLI (openclaw#42256) macOS: add chat model selector and persist thinking (openclaw#42314) fix: clear pnpm prod audit vulnerabilities fix(build): restore full gate fix(gateway): split conversation reset from admin reset ...
Merged via squash. Prepared head SHA: 00e2ad8 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
Merged via squash. Prepared head SHA: 00e2ad8 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
Merged via squash. Prepared head SHA: 00e2ad8 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
Merged via squash. Prepared head SHA: 00e2ad8 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
Merged via squash. Prepared head SHA: 00e2ad8 Co-authored-by: ngutman <[email protected]> Co-authored-by: ngutman <[email protected]> Reviewed-by: @ngutman
Summary
Describe the problem and fix in 2–5 bullets:
gateway.remote.token, where to find the gateway token on the host, or why one Mac connected while a fresh client would still be rejected.Change Type (select all)
Scope (select all touched areas)
Linked Issue/PR
User-visible / Behavior Changes
openclaw config get gateway.auth.token,OPENCLAW_GATEWAY_TOKEN, andopenclaw doctor --generate-gateway-token.Connected via paired devicefrom generic gateway readiness.Security Impact (required)
Yes/No): NoYes/No): YesYes/No): NoYes/No): NoYes/No): NoYes, explain risk + mitigation:The PR changes only how macOS classifies and presents existing gateway auth outcomes. Shared tokens are still stored/resolved through existing config paths, and the new UI copy is explicit about the token living on the gateway host.
Repro + Verification
Environment
apps/macoswss://and SSH tunnelgateway.auth.mode=token; local macOS app tested both with and without stored device-token stateSteps
gateway.remote.tokenvalue.Expected
Actual
Evidence
Attach at least one:
Human Verification (required)
What you personally verified (not just CI), and how:
swift test --package-path apps/macos --filter OnboardingRemoteAuthPromptTestsswift test --package-path apps/macos --filter GatewayChannelConnectTestsOPENCLAW_STATE_DIRand no stored device token returnsunauthorized: gateway token missing (provide gateway auth token).Review Conversations
If a bot review conversation is addressed by this PR, resolve that conversation yourself. Do not leave bot review conversation cleanup for maintainers.
Compatibility / Migration
Yes/No): YesYes/No): NoYes/No): NoFailure Recovery (if this breaks)
apps/macos/Sources/OpenClaw/RemoteGatewayProbe.swift, onboarding/settings auth prompt handling, and the structured connect-auth plumbing inapps/shared/OpenClawKit.Risks and Mitigations
List only real risks for this PR. Add/remove entries as needed. If none, write
None.