Skip to content

fix(device-pair): mobile pairing rejects local IPv6 cleartext URLs#101008

Merged
steipete merged 2 commits into
openclaw:mainfrom
zhangguiping-xydt:fix/problem-device-pair-ipv6-local-cleartext
Jul 6, 2026
Merged

fix(device-pair): mobile pairing rejects local IPv6 cleartext URLs#101008
steipete merged 2 commits into
openclaw:mainfrom
zhangguiping-xydt:fix/problem-device-pair-ipv6-local-cleartext

Conversation

@zhangguiping-xydt

@zhangguiping-xydt zhangguiping-xydt commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Fixes an issue where users pairing a mobile device with a local IPv6 gateway URL would be blocked when the device-pair plugin produced cleartext ws://[fc00::1], ws://[fd7a:115c:a1e0::1], or ws://[fe80::1] setup URLs. The plugin already allowed .local, RFC1918 IPv4, and IPv4 link-local addresses, but treated IPv6 ULA and IPv6 link-local literals as non-local cleartext endpoints and stopped /pair before issuing a setup code.

Why This Change Was Made

The cleartext pairing guard now recognizes normalized IPv6 literals in the local ULA fc00::/7 and link-local fe80::/10 ranges. Public IPv6, deprecated site-local-style fec0::/10 addresses, Tailscale CGNAT cleartext URLs, and public hostnames still fail closed with the existing secure URL guidance.

User Impact

Operators on IPv6-capable local networks can use local IPv6 LAN/link-local gateway addresses in mobile setup codes without switching to TLS or advertising a different host. Non-local cleartext pairing URLs remain rejected, so public mobile pairing still requires wss:// or Tailscale Serve/Funnel.

Evidence

  • pnpm exec vitest run extensions/device-pair/index.test.ts — passed, 59 tests.

  • pnpm exec vitest run extensions/device-pair/index.test.ts -t 'non-LAN IPv6 cleartext' — passed, 3 tests covering public IPv6, fe7f::1 just below fe80::/10, and deprecated site-local fec0::/10 rejection.

  • pnpm exec oxfmt --check --threads=1 extensions/device-pair/index.test.ts — passed.

  • pnpm exec oxlint extensions/device-pair/index.test.ts — passed.

  • Runtime command proof using the real bundled plugin loader and /pair command:

    ALLOW ws://[fc00::1]:18789
    ALLOW ws://[fd7a:115c:a1e0::1]:18789
    ALLOW ws://[fe80::1]:18789
    ALLOW ws://[febf::1]:18789
    REJECT ws://[2001:db8::1]:18789
    REJECT ws://[fec0::1]:18789
    
  • Isolated pnpm gateway:dev startup proof loaded the patched device-pair plugin and reached ready:

    http server listening (9 plugins: acpx, browser, canvas, device-pair, file-transfer, memory-core, ollama, phone-control, talk-voice; 22.3s)
    ready
    

@clawsweeper

clawsweeper Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 6, 2026, 3:11 PM ET / 19:11 UTC.

Summary
The PR updates the bundled device-pair plugin to allow local IPv6 ULA/link-local cleartext pairing URLs and adds allow/reject regression tests for IPv6 setup-code issuance.

PR surface: Source +13, Tests +48. Total +61 across 2 files.

Reproducibility: yes. source-reproducible: current main routes /pair setup-code issuance through validateMobilePairingUrl, and the device-pair cleartext host guard lacks an IPv6 ULA/link-local branch, so ws://[fc00::1] is rejected before setup token issuance.

Review metrics: 1 noteworthy metric.

  • Cleartext pairing policy: 2 IPv6 local ranges allowed; 3 non-local IPv6 cases rejected. The PR changes a bootstrap-token URL guard, so maintainers should see that both the newly allowed ranges and the still-rejected boundary cases are covered before merge.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
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:

  • none.

Next step before merge

  • [P2] No repair lane is needed; this open PR already contains the focused code and tests, so ordinary maintainer review and merge handling are the next action.

Security
Cleared: No concrete security or supply-chain concern found; the cleartext expansion is limited to existing local IPv6 ULA/link-local policy boundaries and retains non-local rejection coverage.

Review details

Best possible solution:

Land the focused plugin-side IPv6 local cleartext allowance with its allow/reject regression coverage, while keeping public IPv6, Tailscale CGNAT IPv4, and public hostnames on the secure-URL path.

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

Yes, source-reproducible: current main routes /pair setup-code issuance through validateMobilePairingUrl, and the device-pair cleartext host guard lacks an IPv6 ULA/link-local branch, so ws://[fc00::1] is rejected before setup token issuance.

Is this the best way to solve the issue?

Yes. The PR is the best narrow fix for this plugin because it updates the existing device-pair guard to match sibling setup-code and Android local-cleartext policy without crossing the extensions plugin boundary; a future shared SDK helper could reduce drift but is not required for this repair.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 2f89de81655a.

Label changes

Label justifications:

  • P2: This is a focused user-facing device-pairing bug for IPv6 local networks with limited blast radius and a narrow plugin-side fix.
  • 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 (live_output): The PR body includes after-fix live output from the bundled plugin loader /pair command showing IPv6 ALLOW/REJECT behavior plus gateway startup ready output.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes after-fix live output from the bundled plugin loader /pair command showing IPv6 ALLOW/REJECT behavior plus gateway startup ready output.
Evidence reviewed

PR surface:

Source +13, Tests +48. Total +61 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 14 1 +13
Tests 1 48 0 +48
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 62 1 +61

What I checked:

  • Repository policy read: Root AGENTS.md and the scoped extensions/AGENTS.md were read fully; their review-depth and plugin-boundary guidance shaped the review, especially checking sibling setup-code and Android policy while keeping the fix inside the plugin boundary. (AGENTS.md:1, 2f89de81655a)
  • Current main still rejects the reported plugin path: Current main normalizes the host and allows .local, RFC1918 IPv4, and IPv4 link-local in isPrivateLanCleartextHost, but has no IPv6 ULA/link-local branch before validateMobilePairingUrl rejects non-local ws:// URLs. (extensions/device-pair/index.ts:245, 2f89de81655a)
  • Latest release has the same missing branch: v2026.6.11 also shows isPrivateLanCleartextHost without the PR's IPv6 helper, so this is not already shipped in the latest release. (extensions/device-pair/index.ts:260, e085fa1a3ffd)
  • PR implementation is narrowly scoped: At head d26b1d6, the PR adds isPrivateLanIPv6 using node:net isIP plus fc00::/7 and fe80::/10 masks, then wires it into the existing private-LAN cleartext host guard. (extensions/device-pair/index.ts:246, d26b1d6c8308)
  • Regression coverage covers both sides of the policy: The PR tests allow fc00, fd7a, fe80, and febf cleartext URLs and reject 2001:db8, fe7f, and fec0 before issuing setup codes. (extensions/device-pair/index.test.ts:850, d26b1d6c8308)
  • Sibling setup-code policy already treats IPv6 ULA/link-local as local: The core setup-code path's isPrivateLanHost accepts fe80:, fc*, and fd* IPv6 literals as private LAN for mobile-pairing cleartext, so the plugin change aligns with an existing OpenClaw sibling policy rather than adding a new cross-boundary rule. (src/pairing/setup-code.ts:107, 2f89de81655a)

Likely related people:

  • obviyus: GitHub metadata and git history tie merged PR fix(pairing): align mobile setup with secure endpoints #60128 and commit a2b5352 to the adjacent mobile private-LAN cleartext policy in setup-code, Android resolver/security, and docs. (role: sibling policy introducer; confidence: high; commits: a2b53522eb71, 9e58a0892ba0; files: src/pairing/setup-code.ts, src/pairing/setup-code.test.ts, apps/android/app/src/main/java/ai/openclaw/app/gateway/GatewayHostSecurity.kt)
  • steipete: Git history shows Peter Steinberger carried recent device-pair refactors and cleanup around the same bundled plugin entrypoint and tests after the pairing-policy work landed. (role: recent device-pair area contributor; confidence: medium; commits: 05da802e1cdc, 18db265ef356, 775fa78b1e51; files: extensions/device-pair/index.ts, extensions/device-pair/index.test.ts)
  • vincentkoc: The checked-out history carries the current device-pair and setup-code files through the v2026.6.11 release commit authored by Vincent Koc, though that commit appears broad and is weaker ownership evidence than the feature-specific commits. (role: recent release/current-main carrier; confidence: low; commits: e085fa1a3ffd; files: extensions/device-pair/index.ts, extensions/device-pair/index.test.ts, src/pairing/setup-code.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.
Review history (1 earlier review cycle)
  • reviewed 2026-07-06T17:22:34.104Z sha 492d77d :: needs maintainer review before merge. :: none

@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. P2 Normal backlog priority with limited blast radius. labels Jul 6, 2026
@vincentkoc vincentkoc self-assigned this Jul 6, 2026
@steipete
steipete merged commit e80e8a2 into openclaw:main Jul 6, 2026
93 of 94 checks passed
@steipete

steipete commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 7, 2026
…penclaw#101008)

* fix(device-pair): allow local IPv6 pairing URLs

* test(device-pair): cover IPv6 cleartext lower bound
giodl73-repo pushed a commit to giodl73-repo/openclaw that referenced this pull request Jul 8, 2026
…penclaw#101008)

* fix(device-pair): allow local IPv6 pairing URLs

* test(device-pair): cover IPv6 cleartext lower bound
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

extensions: device-pair P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S 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.

3 participants