Skip to content

fix(connect): refuse secret entry and retire the phone full client - #2546

Merged
DoodleBears merged 9 commits into
mainfrom
codex/2541-connect-secret-safety
Oct 22, 2026
Merged

DoodleBears merged 9 commits into
mainfrom
codex/2541-connect-secret-safety

Conversation

@DoodleBears

@DoodleBears DoodleBears commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Requested by Vain. Refs #2541, #2542. The superseded #2533 adapter has been replaced by the canonical source-Host message implementation merged in #2538. Current main integration preserves that owner and the Track A secret refusal.

Track A claim · Track B original ADR claim · Audit · Proposed ADR-0244

Why the change

Connect currently exposes plaintext at Cloudflare, so this change prevents supported clients from sending known credential-entry methods, refuses them at the Host gateway, and removes the phone's full Host WebView as requested by Vain.

Special things to note

  • Large blast radius; two-way code door: affects Device Gateway HTTP/mux, remote cards and phone navigation; no data migration. Reverting restores unsafe secret entry, so the safe operational rollback is to disable Connect or retain the refusal. Review provenance, parser/buffer limits, revocation, ordinary streams and removal of legacy WebView routes.
  • Interim restriction, not E2EE. Modified clients can still send plaintext to Cloudflare; chat, files, viewer input, pairing credentials and responses are not made confidential. Generic settings, Cloud Connections and IM setup are refused at whole-method granularity. This PR carries the original ADR proposal; Vain subsequently approved its implementation, now in follow-up #2547. Track A itself still adds no E2EE; native feature-gap acceptance remains separate. Full phone WebView removal ships with Track A on every route, per Vain's confirmation.
  • Integration and authorization: Vain explicitly authorized merge on 2026-10-22 and deferred the integrated Simulator checks to the shared post-merge batch, with screenshots to be added to this PR afterward. Current integration types, 35 secret/card regressions, related message tests, lint and format pass; current-head full CI passed for eb93f673b0c2; merged as f267b7022951. Stacked feat(connect): encrypt paired-device traffic with pinned Noise XK #2547 contains real Cloudflare/iOS password and pairing evidence. Physical-device, Android native, deployed account enrollment and full release qualification remain separate; merge does not authorize deployment. Historical checks below retain their original revisions.

Change outline

supported phone / remote Web Client
  └─ selected Connect route → shared secret policy → refuse before serialization/network
cloudflared-only origin
  └─ overwrite caller route tags → process-local provenance
       └─ Device Gateway admission
            ├─ marked unary/mux method → secret-route-refused
            └─ allowed method → native DSH dispatch/schema/permissions
- Phone full-client screen, actions and authenticated source
- Device /web/ HTML, cookie sessions, mux and viewer socket registrations
+ Bilingual Host/Tailscale guidance and Connect private-input refusal
+ Native daily routines remain; unsupported advanced editing points to the Host
+ Proposed Noise XK / pinned Host key / explicit device approval design and gap inventory

Native DSH 0.2.1-rc.2: all eight marked methods refused on unary and mux at the real local Connect origin; roster unary/stream allowed; loopback credential set/unset allowed; removed full-client route returns 404. CLI private-input submission through stdin accepted a synthetic value and canonical status became configured. Phone-web daily routine edit/pause/resume/run/history/delete/create/preview passed. Remote card has zero password fields, disabled submit, and no page errors. Carrier mapping is synthetic local QA, not a live Cloudflare/Tailscale test. Model-created card used deepseek-official/deepseek-flash (DeepSeek-V4.1-Flash).

Earlier broad local testing observed a source-policy timeout, docs public-surface build failure, and a daylight assertion also reproduced on the baseline; it was stopped without a full-suite pass. Full CI 39659766544 passed for prior head b842d3ce0750b5085106defef21c4d4eb0112f81. Evidence provenance and remaining journeys.

Remote private input — cropped 1280 × 800 browser viewport

Before: editable password field. After: field absent, submission disabled, Host/Tailscale guidance. Real Web Client; synthetic hostname mapped to the actual isolated Connect origin.

Light — before / after

Private input before, light

Private input after, light

Dark — before / after

Private input before, dark

Private input after, dark

Phone settings — Expo Web 390 × 844, scale 3

The full-client entry is removed. These are phone-web captures, not native-device evidence.

Light — before / after

Phone settings before, light

Phone settings after, light

Dark — before / after

Phone settings before, dark

Phone settings after, dark

Advanced routine — Expo Web 390 × 844, scale 3

The full-client edit action is removed; the Host-client notice remains. These are phone-web captures, not native-device evidence.

Light — before / after

Advanced routine before, light

Advanced routine after, light

Dark — before / after

Advanced routine before, dark

Advanced routine after, dark

Native screenshots for chat/create/Activity entrances, private-input guidance, old full-client links and Browser/Computer are pending because the shared device queue is paused by the Human for combined acceptance. Review path: Settings → chat overflow/private input → Activity request → create menu → daily/advanced routines → old /full-client link, in both themes.

Agent trace: implementation codex/local/01a15f6b-a5c1-7db2-b5b1-a33a1153fbc6; continuation, integration and evidence codex/local/01a15fc3-2dc9-7e13-a9c5-8ca7f162d141.

claude and others added 6 commits October 21, 2026 16:17
Remote messages now go through ChannelMessageBody. A RemoteMessageHost
context gives the cards Host-scoped actions over the paired Host client,
loads attachments with the device credential, and replaces the local
open-channel guard with the remote chat's own.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkE8f7sBeoRLEF79cccPAV
Refs #2541; proposes ADR for #2542. Reported by Vain.

Issue: #2541

Issue: #2542

Agent-Task: codex/local/01a15f6b-a5c1-7db2-b5b1-a33a1153fbc6

Agent-Task: codex/local/01a15fc3-2dc9-7e13-a9c5-8ca7f162d141
Refs #2541, #2542

Agent-Task: codex/local/01a15fc3-2dc9-7e13-a9c5-8ca7f162d141
Issue: #2541

Agent-Task: codex/local/01a15fc3-2dc9-7e13-a9c5-8ca7f162d141
@DoodleBears DoodleBears added the ci:full Run the complete verification test plan for this pull request label Oct 21, 2026
@DoodleBears DoodleBears self-assigned this Oct 21, 2026
@coderabbitai

coderabbitai Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Note

Currently processing new changes in this PR. This may take a few minutes, please wait...

⚙️ Run configuration
  • Configuration used: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 0cf486a7-b54f-4542-ba88-6b9ff4be1771
📥 Commits

Reviewing files that changed from the base of the PR and between b54b218 and eb93f67.

⛔ Files ignored due to path filters: 19
  • .github/pr-screenshots/2541/private-after-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/private-after-light.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/private-before-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/private-before-light.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/routine-after-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/routine-after-light.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/routine-before-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/routine-before-light.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/settings-after-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/settings-after-light.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/settings-before-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/2541/settings-before-light.png is excluded by !**/*.png
  • .github/pr-screenshots/remote-message-rendering/approved-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/remote-message-rendering/approved-light.png is excluded by !**/*.png
  • .github/pr-screenshots/remote-message-rendering/image-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/remote-message-rendering/image-light.png is excluded by !**/*.png
  • .github/pr-screenshots/remote-message-rendering/pending-dark.png is excluded by !**/*.png
  • .github/pr-screenshots/remote-message-rendering/pending-light.png is excluded by !**/*.png
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing: 71
  • .agents/skills/dsh-dev/SKILL.md
  • .agents/skills/verify-deepseekbot/features/phone-pairing.md
  • .agents/skills/verify-deepseekbot/features/phone-routines.md
  • .agents/skills/verify-deepseekbot/features/remote-hosts.md
  • .github/pr-screenshots/2541/README.md
  • apps/mobile/DESIGN.md
  • apps/mobile/README.md
  • apps/mobile/app/_layout.tsx
  • apps/mobile/app/full-client.tsx
  • apps/mobile/app/inbox/[id].tsx
  • apps/mobile/app/settings/index.tsx
  • apps/mobile/src/host/client.ts
  • apps/mobile/src/host/conversation.ts
  • apps/mobile/src/host/full-client.ts
  • apps/mobile/src/host/route.ts
  • apps/mobile/src/ui/chat/conversation-screen.tsx
  • apps/mobile/src/ui/chat/private-input-card.tsx
  • apps/mobile/src/ui/chat/routine-screen.tsx
  • apps/mobile/src/ui/chat/routine-sheet.tsx
  • apps/mobile/src/ui/full-client-view.tsx
  • apps/mobile/src/ui/open-full-client.tsx
  • apps/mobile/src/ui/settings-view.tsx
  • apps/mobile/src/ui/shell/bottom-navigation.tsx
  • apps/mobile/src/ui/strings.ts
  • apps/mobile/test/attention-actions.test.ts
  • apps/mobile/test/conversation-navigation.test.tsx
  • apps/mobile/test/conversation-streaming-rows.test.tsx
  • apps/mobile/test/conversation.test.ts
  • apps/mobile/test/full-client-back-android.test.tsx
  • apps/mobile/test/full-client.test.ts
  • apps/mobile/test/host-client.test.ts
  • apps/mobile/test/routine-sheet.test.tsx
  • apps/mobile/test/settings-sheet.test.tsx
  • apps/mobile/test/style-guard.test.ts
  • apps/mobile/test/usage-screen.test.tsx
  • changes/2500-remote-message-rendering.md
  • changes/2541-connect-secret-safety.md
  • docs/adr/0199-paired-devices-reach-the-host-through-a-same-listener-device-gateway.md
  • docs/adr/0241-hosted-connect-reaches-the-host-through-a-managed-tunnel.md
  • docs/adr/0242-a-browser-pairs-other-computers-through-their-device-gateway.md
  • docs/adr/0244-connect-encrypts-device-traffic-against-pinned-host-keys.md
  • docs/architecture/botharness-architecture.md
  • docs/bot-cli.md
  • docs/bot-cli.zh.md
  • docs/research/2026-10-22-connect-secret-safety-audit.md
  • packages/browser/src/index.ts
  • packages/browser/src/viewer.ts
  • packages/browser/test/viewer.test.ts
  • packages/client/src/client/actions.ts
  • packages/client/src/client/bridge.ts
  • packages/client/src/client/locale.ts
  • packages/client/src/client/private-input-card.tsx
  • packages/client/test/channel-user-question.test.ts
  • packages/computer/src/index.ts
  • packages/core/package.json
  • packages/core/src/bridge/rpc.ts
  • packages/core/src/bridge/secret-route.ts
  • packages/core/src/devices/connect-mux.ts
  • packages/core/src/devices/connect.ts
  • packages/core/src/devices/gateway.ts
  • packages/core/src/devices/mount.ts
  • packages/core/src/devices/route-context.ts
  • packages/core/src/devices/rpc-policy.ts
  • packages/core/src/http/viewer-proxy.ts
  • packages/core/src/plugin.ts
  • packages/core/test/connect-secret-route.test.ts
  • packages/core/test/device-gateway.test.ts
  • packages/core/test/device-route-context.test.ts
  • scripts/cli-ui-inventory.json
  • scripts/e2e-mobile-routines-web.mjs
  • scripts/verification-inventory.json
+--------------------------------------------------+
| I ran the tests. They filed a restraining order. |
+--------------------------------------------------+
  \
   \   (\__/)
       (•ㅅ•)
       /   づ
✨ Finishing Touches
📝 Generate docstrings
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@DoodleBears

DoodleBears commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor Author

Historical preview — superseded by the current handoff. This image explains Track A head f8bace65e66fa1ec8f34783623b3eebe9f92a894, not the current head. Track A is now b842d3ce0750b5085106defef21c4d4eb0112f81; the intervening change only repairs verification inventory links, and full CI39659766544 passes.

The image’s “Track B remains ADR-only / approval pending” statement is stale: Vain approved the complete Noise XK implementation and stacked delivery, now in Draft #2547. Full phone WebView removal remains in Track A. Native, real-network and Human QA remain unrun; neither PR is merged or deployed.

The local Chinese HTML was refreshed to the current Track A head, links to #2547, and was checked at desktop/narrow widths. Interactive HTML remains local, so shared HTML delivery is not claimed. See #2547 for current code, seven verified GitHub-rendered screenshots and the two-axis review handoff.

Historical static preview (review aid, not runtime evidence):

Historical Track A explainer at f8bace65e66f

Issue: #2541

Agent-Task: codex/local/01a15fc3-2dc9-7e13-a9c5-8ca7f162d141
Preserve #2538 canonical message/resource ownership while applying Track A secret-entry refusal. Remove the superseded #2533 adapter and retain current notification/viewer behavior.

Issue: #2541
Agent-Task: codex/local/01a15fc3-2dc9-7e13-a9c5-8ca7f162d141
Issue: #2541
Agent-Task: codex/local/01a15fc3-2dc9-7e13-a9c5-8ca7f162d141
@DoodleBears
DoodleBears marked this pull request as ready for review October 22, 2026 06:16
@DoodleBears
DoodleBears merged commit f267b70 into main Oct 22, 2026
12 of 13 checks passed
@DoodleBears
DoodleBears deleted the codex/2541-connect-secret-safety branch October 28, 2026 04:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:full Run the complete verification test plan for this pull request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants