Skip to content

fix: webhook exposure checks bug#75465

Merged
steipete merged 2 commits intomainfrom
clawsweeper/clawsweeper-commit-openclaw-openclaw-b2aac178d6da
May 1, 2026
Merged

fix: webhook exposure checks bug#75465
steipete merged 2 commits intomainfrom
clawsweeper/clawsweeper-commit-openclaw-openclaw-b2aac178d6da

Conversation

@clawsweeper
Copy link
Copy Markdown
Contributor

@clawsweeper clawsweeper Bot commented May 1, 2026

Summary

Found one concrete bug in the new webhook exposure checks: IPv6 loopback and unique-local webhook URLs are still treated as public/reachable, even though the commit and docs say local/private webhook URLs fail before joins.

What ClawSweeper Is Fixing

  • Medium: IPv6 local/private webhook URLs pass the new exposure preflight (bug)
    • File: extensions/voice-call/src/webhook-exposure.ts:45
    • Evidence: isProviderUnreachableWebhookUrl() passes new URL(webhookUrl).hostname into isLocalOnlyWebhookHost(). In Node, IPv6 URL hostnames are bracketed, for example new URL("http://[::1]:3334/voice/webhook").hostname returns "[::1]", not "::1". The helper compares against "::", "::1", and host.startsWith("fc") || host.startsWith("fd"), so bracketed "[::1]", "[fc00::1]", and "[fd00::1]" all return false. The duplicate Google Meet helper has the same behavior at extensions/google-meet/src/setup.ts:50, and getVoiceCallWebhookExposureCheck() then reports ok: true for those publicUrl values at extensions/google-meet/src/setup.ts:65.
    • Impact: voicecall setup, googlemeet setup --transport twilio, and the runtime fail-closed guard can approve publicUrl values such as http://[::1]:3334/voice/webhook or http://[fd00::1]/voice/webhook. Twilio/Telnyx/Plivo callbacks will not be able to reach those URLs, so the user gets a green setup check and may start a join/call that cannot receive provider webhooks.
    • Suggested fix: normalize URL hostnames before classification, for example strip IPv6 brackets and use a real IP classifier (node:net.isIP plus range checks, or an existing shared SSRF/private-IP helper). Add regression tests for ::, ::1, fc00::/7, fd00::/8, and IPv4-mapped loopback/private forms in both the shared voice-call helper and Google Meet setup path, or centralize the helper so they cannot drift.
    • Confidence: high

Expected Repair Surface

  • extensions/voice-call/src/webhook-exposure.ts
  • extensions/google-meet/index.test.ts
  • extensions/google-meet/src/setup.ts
  • extensions/voice-call/index.test.ts
  • extensions/voice-call/src/cli.ts
  • extensions/voice-call/src/runtime.test.ts
  • extensions/voice-call/src/runtime.ts

Source And Review Context

  • ClawSweeper report: https://github.com/openclaw/clawsweeper/blob/main/records/openclaw-openclaw/commits/b2aac178d6da6ccd8228d4f8e20239153da4dcb9.md

  • Commit under review: b2aac17

  • Latest main at intake: 7340c03

  • Original commit author: Peter Steinberger

  • GitHub author: @steipete

  • Highest severity: medium

  • Review confidence: high

  • Diff: 464e57360262b7e0f9a705431bedd402fe8c356b..b2aac178d6da6ccd8228d4f8e20239153da4dcb9

  • Changed files: CHANGELOG.md, docs/plugins/google-meet.md, extensions/google-meet/index.test.ts, extensions/google-meet/src/setup.ts, extensions/voice-call/index.test.ts, extensions/voice-call/src/cli.ts, extensions/voice-call/src/runtime.test.ts, extensions/voice-call/src/runtime.ts, extensions/voice-call/src/webhook-exposure.ts

  • Code read: Google Meet setup/runtime/tool path, voice-call CLI setup, runtime public webhook guard, new webhook exposure helper, adjacent config/provider contracts, changed tests, relevant Google Meet docs sections.

  • Dependencies/web: no dependency files changed; no web lookup needed.

Expected validation

  • pnpm check:changed

ClawSweeper already ran:

  • pnpm docs:list
  • pnpm install after the first test run showed missing vitest/package.json
  • pnpm test extensions/voice-call/src/runtime.test.ts extensions/voice-call/index.test.ts extensions/google-meet/index.test.ts passed: 3 files, 94 tests.
  • pnpm exec tsx ...extensions/voice-call/src/webhook-exposure.ts... reproduced the IPv6 false-negative.

Known review limits:

  • I did not run the full changed gate; this was a focused report-only review.

ClawSweeper Guardrails

  • Re-check the finding against latest main before changing code.
  • Keep the patch to the narrowest behavior change and matching regression coverage.
  • Do not merge automatically; this PR stays for maintainer review.

ClawSweeper 🐠 replacement reef notes:

  • Cluster: clawsweeper-commit-openclaw-openclaw-b2aac178d6da
  • Source PRs: none
  • Credit: Detected by ClawSweeper commit review for b2aac17.; Original commit author: Peter Steinberger.
  • Validation: pnpm check:changed

fish notes: model gpt-5.5, reasoning medium; reviewed against 68f6b49.

@clawsweeper clawsweeper Bot added clawsweeper Tracked by ClawSweeper automation clawsweeper:commit-finding PR created from a ClawSweeper commit finding labels May 1, 2026
@clawsweeper
Copy link
Copy Markdown
Contributor Author

clawsweeper Bot commented May 1, 2026

Codex review: needs maintainer review before merge.

What this changes:

The PR normalizes Voice Call and Google Meet webhook host checks for bracketed IPv6 and IPv4-mapped private or loopback URLs, adds regression coverage, and updates the changelog entry.

Maintainer follow-up before merge:

This is already an open implementation PR with a narrow, reviewable fix; the remaining action is maintainer review plus waiting for final required checks, not a separate automated repair branch.

Security review:

Security review cleared: The diff tightens webhook exposure classification and adds tests/changelog only; it does not change dependencies, workflows, permissions, scripts, package resolution, or secret handling.

Review details

Best possible solution:

Land this PR or an equivalent narrow fix after CI: normalize webhook hostnames before local/private classification in both Voice Call and Google Meet setup, keep the regression tests, and consider a later shared-helper cleanup only if this duplicated logic starts drifting again.

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

Yes. Current main can be reproduced with Node URL parsing for http://[::1], http://[fd00::1], and IPv4-mapped forms, then tracing those bracketed hostnames into the existing classifier comparisons.

Is this the best way to solve the issue?

Yes. The PR is the narrowest maintainable fix for the reported behavior: it corrects the classifier inputs and covers the CLI/runtime/Google Meet setup paths without changing provider contracts or adding dependencies.

Acceptance criteria:

  • pnpm check:changed
  • pnpm test extensions/voice-call/src/runtime.test.ts extensions/voice-call/index.test.ts extensions/google-meet/index.test.ts

What I checked:

  • Current main Voice Call classifier is still unnormalized: isProviderUnreachableWebhookUrl() passes new URL(webhookUrl).hostname into isLocalOnlyWebhookHost(), whose comparisons expect unbracketed ::, ::1, fc, and fd forms. (extensions/voice-call/src/webhook-exposure.ts:45, ec1b96cdfa08)
  • Current main Google Meet setup has the same duplicate helper: The Google Meet setup path uses the same unnormalized hostname checks before deciding whether twilio-voice-call-webhook is usable. (extensions/google-meet/src/setup.ts:50, ec1b96cdfa08)
  • Node URL parsing reproduces the mismatch: Node reports IPv6 URL hostnames as bracketed values such as [::1] and [fd00::1], while an IPv4-mapped URL is normalized to [::ffff:7f00:1]; those strings do not match current main's unbracketed checks.
  • Runtime guard depends on the classifier: The Voice Call runtime refuses provider-required public webhooks through providerRequiresPublicWebhook() plus isProviderUnreachableWebhookUrl(), so the classifier result gates startup safety for Twilio/Telnyx/Plivo. (extensions/voice-call/src/runtime.ts:391, ec1b96cdfa08)
  • PR patch covers the reported gap: The head patch strips IPv6 brackets, recognizes IPv4-mapped forms, applies the same change to the Google Meet setup helper, and adds tests for ::, ::1, fc00::/7, fd00::/8, and IPv4-mapped private addresses. (extensions/voice-call/src/webhook-exposure.test.ts:5, 68f6b494c852)
  • Feature history points to the recent webhook exposure commit: Git blame attributes both current classifiers to b2aac178d6da6ccd8228d4f8e20239153da4dcb9, the recent fix: tighten meet voice-call setup checks commit. (extensions/voice-call/src/webhook-exposure.ts:22, b2aac178d6da)

Likely related people:

  • steipete: Git blame attributes the current Voice Call and Google Meet webhook exposure helpers to the recent setup-check commit, and nearby history shows continued maintenance of the Meet/Voice Call path. (role: introduced behavior and recent maintainer; confidence: high; commits: b2aac178d6da, ffcc0d1fe171, ae07d57f9d5f; files: extensions/voice-call/src/webhook-exposure.ts, extensions/google-meet/src/setup.ts, extensions/voice-call/src/runtime.ts)

Remaining risk / open question:

  • The full PR check suite was still in progress at review time, so merge should wait for required checks even though the source review found no blocking defect.

Codex review notes: model gpt-5.5, reasoning high; reviewed against ec1b96cdfa08.

@steipete steipete force-pushed the clawsweeper/clawsweeper-commit-openclaw-openclaw-b2aac178d6da branch from 68f6b49 to ccb06bb Compare May 1, 2026 06:27
@steipete steipete merged commit be91863 into main May 1, 2026
13 checks passed
@steipete steipete deleted the clawsweeper/clawsweeper-commit-openclaw-openclaw-b2aac178d6da branch May 1, 2026 06:28
@steipete
Copy link
Copy Markdown
Contributor

steipete commented May 1, 2026

Landed via squash after tightening the implementation to reuse the existing SSRF hostname/IP classifier.

  • Local repro before fix: bracketed IPv6 loopback/ULA and IPv4-mapped loopback returned reachable; fcloud.example was rejected by the old fc prefix check.
  • Focused tests: pnpm test extensions/voice-call/src/webhook-exposure.test.ts extensions/voice-call/src/runtime.test.ts extensions/voice-call/index.test.ts extensions/google-meet/index.test.ts
  • Extra touched-test proof: pnpm test extensions/google-meet/src/cli.test.ts extensions/google-meet/index.create.test.ts
  • Broad gate: Testbox OPENCLAW_TESTBOX=1 pnpm check:changed passed on tbx_01kqh3d9hbsskda12r4ngesv40.
  • Source head: ccb06bb
  • Merge commit: be91863

Thanks @clawsweeper, @donkeykong91, and @PfanP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: voice-call Channel integration: voice-call clawsweeper:commit-finding PR created from a ClawSweeper commit finding clawsweeper Tracked by ClawSweeper automation plugin: google-meet size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant