Skip to content

Gateway: allow extension origins in browser allowlist#38290

Merged
steipete merged 1 commit into
openclaw:mainfrom
brunowowk:feature/allow-chrome-extension-origins
Jul 9, 2026
Merged

Gateway: allow extension origins in browser allowlist#38290
steipete merged 1 commit into
openclaw:mainfrom
brunowowk:feature/allow-chrome-extension-origins

Conversation

@brunowowk

@brunowowk brunowowk commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

What Problem This Solves

Desktop shells and browser extensions send valid browser Origin values such as tauri://localhost, electron://localhost, app://localhost, or chrome-extension://<id>. JavaScript's URL parser reports URL.origin === "null" for these hosted non-standard schemes, so the Gateway could not match them against an exact gateway.controlUi.allowedOrigins entry. Operators were forced to choose between a broken app and the much broader "*" allowlist.

Fixes #46520. Also covers the root cause reported in #35035.

Why This Change Was Made

The Gateway now derives scheme://authority only for hosted schemes whose parsed origin is opaque, while retaining the standard serialized origin for HTTP(S). The raw input must first be an origin and nothing more: paths, queries, fragments, credentials, hostless schemes, dot-segment normalization, and backslash path separators are rejected before URL canonicalization.

This is deliberately exact matching, not a scheme wildcard or prefix match. tauri://localhost grants only that origin; it does not grant tauri://localhost/path, another authority, Origin: null, or arbitrary Tauri origins. Existing wildcard, private same-origin, tailnet, host-header fallback, token/device authentication, and local-loopback rules remain unchanged.

User Impact

  • Tauri, Electron, app-protocol, and Chrome-extension clients can use a narrow exact origin allowlist.
  • Users no longer need gateway.controlUi.allowedOrigins=["*"] solely because their desktop/browser shell uses a non-standard scheme.
  • Malformed URL-like values cannot inherit an allowlisted authority through parser normalization.
  • No new config key, migration, permission, or public API surface.

Evidence

  • Blacksmith Testbox tbx_01kx3a3cqcgztce1p3rc9wrqmp / Actions 29014889369: 146/146 origin-validator and real Gateway browser-auth tests passed.
  • Real Gateway coverage connects with exact tauri://localhost and rejects non-matching or malformed variants.
  • Focused cases cover HTTP(S), Chrome extension, Tauri, Electron, app schemes, paths, dot segments, percent-encoded dots, backslashes, query, fragment, credentials, file:, data:, wildcard, private same-origin, host fallback, and local-loopback behavior.
  • Fresh autoreview: clean after fixing two canonicalization bypasses found during review (dot segments and backslashes).
  • git diff --check and repository formatting passed.

Compatibility / Recovery

Backward compatible for valid existing origins. Reverting the single Gateway origin-parser change restores prior behavior; no stored data or config migration is involved.

AI Assistance

Maintainer-refactored and reviewed with Codex. Contributor credit is preserved in the commit trailer.

@greptile-apps

greptile-apps Bot commented Mar 6, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a bug where chrome-extension:// (and other non-standard scheme) origins could never be exactly allowlisted in gateway.controlUi.allowedOrigins because the WHATWG URL.origin property returns the string "null" for those schemes, causing all extension origins to collapse to the same value during comparison.

The fix introduces normalizeOriginForMatch, which uses url.origin for standard schemes and falls back to ${url.protocol}//${url.host} for non-standard ones. Critically, the same normalization is applied to both the incoming request origin and the configured allowlist entries via the new normalizeAllowedOrigin helper, so matching is symmetric and consistent.

Key observations:

  • The fix is minimal and well-scoped — no wildcard expansion, no relaxation of the Origin: null literal rejection, no changes to token/device auth paths.
  • The semantic shift in normalizeAllowedOrigin — invalid/unparseable allowlist entries now return null and are silently dropped rather than being kept as raw lowercase strings — is strictly an improvement, though operators with config typos (e.g. htps://...) will no longer see those entries silently "match nothing"; they are just removed.
  • The file:// scheme would also go through the fallback path and normalize to file:// (empty host), but browsers send Origin: null for file:// resources, which is already rejected by the existing trimmed === "null" guard in parseOrigin. No bypass is possible.
  • Unit tests cover the new allowlisted/rejected extension origin cases; the end-to-end handshake test in server.auth.browser-hardening.test.ts confirms the full integration path through the Gateway WS server.

Confidence Score: 5/5

  • This PR is safe to merge — it is a narrow, backward-compatible bug fix with symmetric normalization and no new attack surface.
  • The change is small and focused. Both the incoming origin and allowlist entries go through the same new normalization path, so matching remains consistent. The existing Origin: null literal rejection guard is untouched. No wildcard expansion or new auth bypass vectors are introduced. Tests cover the new code path at both unit and integration level.
  • No files require special attention.

Last reviewed commit: e252c8a

@Takhoffman
Takhoffman requested a review from a team as a code owner March 24, 2026 20:16
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Apr 21, 2026
@steipete

Copy link
Copy Markdown
Contributor

Codex deep review: this is still a valid current bug and this PR is the right narrow fix for exact chrome-extension://<id> allowlist entries.

Current main still compares allowedOrigins against url.origin; for chrome-extension://..., WHATWG URL returns the opaque origin string "null", so an exact configured extension origin cannot match. The PR fixes that by normalizing both sides through the same fallback (protocol//host) for opaque-origin schemes, and it includes both unit coverage and a gateway WebSocket auth/hardening integration test.

Scope looks correct: this should close #52477 / #43596-style exact-origin failures. It intentionally does not implement scheme wildcards like chrome-extension://*; keep #39739 separate for that product/security decision.

One merge note: rebase onto current main before landing and keep the test names/fixtures aligned with the current src/gateway/origin-check.test.ts style. The current issue is not fixed on main yet, so I would not close #52477 until this or an equivalent patch lands.

@openclaw-barnacle openclaw-barnacle Bot removed the stale Marked as stale due to inactivity label Apr 25, 2026
@clawsweeper

clawsweeper Bot commented Apr 26, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed July 9, 2026, 6:21 AM ET / 10:21 UTC.

Summary
The PR changes Gateway browser-origin matching so exact chrome-extension://<id> entries in gateway.controlUi.allowedOrigins can match, with unit and WebSocket handshake coverage.

PR surface: Source +21, Tests +41. Total +62 across 3 files.

Reproducibility: yes. at source level. Current main compares configured origins against URL.origin, and a Node URL probe shows the reported custom schemes serialize that origin as "null" before exact allowlist matching.

Review metrics: 1 noteworthy metric.

  • Control UI allowlist semantics: 1 existing config interpretation changed. The diff changes how gateway.controlUi.allowedOrigins strings are interpreted for browser-origin Gateway access.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #46520
Summary: This PR is a candidate fix for the exact custom-scheme origin allowlist root cause tracked by the open desktop custom-scheme issue; scheme wildcard support is broader adjacent work.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

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

Rank-up moves:

  • Preserve configured allowlist entries as exact strings except *.
  • [P2] Reject hostless opaque-origin fallbacks such as file: and data:.
  • Rebase over current main while preserving private same-origin Gateway behavior.

Risk before merge

  • [P1] Configured gateway.controlUi.allowedOrigins entries with paths or queries would become whole-origin matches after upgrade, widening an existing browser-origin authorization config.
  • [P1] Hostless opaque schemes such as file: and data: can synthesize broad scheme:// match strings if configured, instead of staying invalid like literal Origin: null.
  • [P1] The PR head conflicts with current main and predates newer Gateway origin behavior such as private same-origin handling, so repair must preserve current-main semantics.

Maintainer options:

  1. Repair parser before merge (recommended)
    Preserve configured allowlist entries as exact trimmed lowercase strings, normalize only incoming hosted opaque origins, reject hostless opaque schemes, and rebase onto current main.
  2. Advance a cleaner sibling only after it clears
    A sibling PR can supersede this one only if it becomes current-main clean, proof-positive, and keeps exact allowlist behavior without broader policy changes.
  3. Accept broader parsing deliberately
    Maintainers could intentionally accept broader configured-origin parsing, but that turns this bug fix into a security and product-policy choice.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Preserve configured `allowedOrigins` as trimmed lowercase exact strings except `*`; normalize incoming parsed opaque origins only when `url.origin === "null"` and `url.host` is non-empty; add regression tests for `https://host/path` staying rejected and hostless `file:`/`data:` origins staying invalid; rebase against current main while preserving private-same-origin behavior.

Next step before merge

  • [P2] Queue repair because the blockers are narrow parser, test, and rebase edits on a maintainer-modifiable branch, not a product-direction choice.

Security
Needs attention: The diff changes Gateway browser-origin authorization and currently broadens configured allowlist semantics plus hostless opaque-origin matching.

Review findings

  • [P1] Keep configured allowlist values exact — src/gateway/origin-check.ts:47
  • [P2] Reject empty-host opaque origins — src/gateway/origin-check.ts:17
Review details

Best possible solution:

Land this or an equivalent current-main fix after keeping configured allowlist strings exact, accepting only hosted opaque incoming origins, rejecting hostless schemes, and preserving current private same-origin behavior.

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

Yes at source level. Current main compares configured origins against URL.origin, and a Node URL probe shows the reported custom schemes serialize that origin as "null" before exact allowlist matching.

Is this the best way to solve the issue?

No, not yet. The parser layer is the right owner boundary, but the patch should keep configured allowlist values exact, reject hostless opaque schemes, and rebase over current main before merge.

Full review comments:

  • [P1] Keep configured allowlist values exact — src/gateway/origin-check.ts:47
    Still present from the prior review: normalizeAllowedOrigin parses every configured entry and stores parseOrigin(...).matchOrigin, so an existing allowedOrigins: ["https://control.example.com/private"] would now accept Origin: https://control.example.com. Current main treats configured entries as exact normalized strings; keep config exact and apply opaque-origin fallback only to incoming hosted origins.
    Confidence: 0.93
  • [P2] Reject empty-host opaque origins — src/gateway/origin-check.ts:17
    Still present from the prior review: the fallback constructs a match string even when url.host is empty, so hostless opaque schemes such as file: or data: can become broad scheme:// allowlist matches. Browser file/data origins should stay invalid; require a non-empty host and add rejection coverage.
    Confidence: 0.88

Overall correctness: patch is incorrect
Overall confidence: 0.92

AGENTS.md: found and applied where relevant.

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

Label changes

Label justifications:

  • P2: The PR targets a bounded Gateway allowlist bug with a security-relevant workaround, but the remaining blockers are focused parser and upgrade-safety fixes.
  • merge-risk: 🚨 compatibility: Parsing configured allowlist entries can change how existing gateway.controlUi.allowedOrigins values with paths or queries behave after upgrade.
  • merge-risk: 🚨 security-boundary: The changed helper decides which browser-origin WebSocket and trusted-proxy HTTP requests may proceed into Gateway authentication.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦞 diamond lobster and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (screenshot): The PR body includes inspected screenshot proof showing an after-fix Chrome extension Gateway connection with the exact extension origin present in gateway.controlUi.allowedOrigins.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes inspected screenshot proof showing an after-fix Chrome extension Gateway connection with the exact extension origin present in gateway.controlUi.allowedOrigins.
  • proof: 📸 screenshot: Contributor real behavior proof includes screenshot evidence. The PR body includes inspected screenshot proof showing an after-fix Chrome extension Gateway connection with the exact extension origin present in gateway.controlUi.allowedOrigins.
Evidence reviewed

PR surface:

Source +21, Tests +41. Total +62 across 3 files.

View PR surface stats
Area Files Added Removed Net
Source 1 25 4 +21
Tests 2 41 0 +41
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 3 66 4 +62

Security concerns:

  • [medium] Allowlist entries with paths become whole-origin matches — src/gateway/origin-check.ts:47
    Parsing configured allowlist strings means a value that current main treats as an inert exact string can become a trusted browser origin after upgrade.
    Confidence: 0.92
  • [medium] Hostless opaque schemes can be allowlisted broadly — src/gateway/origin-check.ts:17
    The fallback returns scheme:// even when the parsed URL has no host, which is too broad for schemes whose browser origins normally serialize as literal null.
    Confidence: 0.86

Acceptance criteria:

  • [P1] pnpm test src/gateway/origin-check.test.ts src/gateway/server.auth.browser-hardening.test.ts.
  • [P1] pnpm check:changed -- src/gateway/origin-check.ts src/gateway/origin-check.test.ts src/gateway/server.auth.browser-hardening.test.ts.
  • [P1] git diff --check.

What I checked:

  • Current-main behavior still has the bug: Current main parses the request origin with new URL(...).origin and compares that value against trimmed configured allowedOrigins, so chrome-extension://... and other opaque origins become "null" before the exact allowlist check. (src/gateway/origin-check.ts:17, e39e628a8416)
  • PR changes configured allowlist parsing: The PR adds normalizeAllowedOrigin and parses each configured allowlist entry through parseOrigin, which turns configured URLs with paths/queries into whole-origin matches instead of preserving exact configured strings. (src/gateway/origin-check.ts:47, e252c8ae62da)
  • Opaque-origin URL probe: A Node URL probe confirmed chrome-extension://abcdefghijklmnop, app://localhost, and tauri://localhost report origin: "null" with non-empty hosts, while file: and data: report origin: "null" with empty hosts.
  • Config contract is security-sensitive: The checked-in config help describes gateway.controlUi.allowedOrigins as full trusted browser origins and warns that wildcard * allows any browser origin, so this setting is a Gateway browser-origin authorization boundary. (src/config/schema.help.ts:590, e39e628a8416)
  • Runtime entry points read the same helper: Gateway WebSocket connect handling calls checkBrowserOrigin with configSnapshot.gateway?.controlUi?.allowedOrigins, so the changed helper controls browser-origin WebSocket admission. (src/gateway/server/ws-connection/message-handler.ts:884, e39e628a8416)
  • Real behavior proof inspected: The attached screenshots show a Chrome extension sidepanel connected after the fix and the redacted config containing the exact chrome-extension://... allowed origin.

Likely related people:

  • steipete: Authored the original Gateway origin-check hardening and several follow-up changes, merged related wildcard allowlist support, commented on this PR, and is currently assigned to it. (role: feature owner / recent reviewer; confidence: high; commits: 66d8117d4483, 223d7dc23d73, d5ae4b83378d; files: src/gateway/origin-check.ts, src/gateway/origin-check.test.ts, src/gateway/server/ws-connection/message-handler.ts)
  • frankekn: Authored the merged wildcard gateway.controlUi.allowedOrigins support that changed the same allowlist helper and tests. (role: adjacent feature contributor; confidence: medium; commits: 1636f7ff5fd7; files: src/gateway/origin-check.ts, src/gateway/origin-check.test.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 (18 earlier review cycles; latest 8 shown)
  • reviewed 2026-07-07T18:48:24.916Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins
  • reviewed 2026-07-08T02:25:53.633Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins
  • reviewed 2026-07-08T05:00:50.732Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins
  • reviewed 2026-07-08T05:43:06.543Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins
  • reviewed 2026-07-09T06:18:41.965Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins
  • reviewed 2026-07-09T07:03:13.690Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins
  • reviewed 2026-07-09T07:08:49.717Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins
  • reviewed 2026-07-09T08:45:43.726Z sha e252c8a :: needs changes before merge. :: [P1] Keep configured allowlist values exact | [P2] Reject empty-host opaque origins

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 9, 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 proof: sufficient ClawSweeper judged the real behavior proof convincing. labels May 9, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 10, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 13, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 13, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 14, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 14, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 15, 2026
@Takhoffman

Copy link
Copy Markdown
Contributor

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper

clawsweeper Bot commented May 19, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🔥 Warming up: real-behavior proof passed; findings, security review, or rank-up moves are still in progress.

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.
What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Maintainer rewrite and proof complete at ed9511d440837f4ba147e813a272b15e54a9633c.

What this solves: browser extensions and desktop shells send hosted custom origins such as chrome-extension://<id>, tauri://localhost, electron://localhost, and app://localhost. WHATWG reports an opaque URL.origin for those schemes, so exact gateway.controlUi.allowedOrigins entries never matched and users fell back to the much broader "*" grant.

The final change keeps current main's existing private-same-origin, tailnet, host-header, token/device-auth, and loopback policy intact. It adds only exact authority-form matching for hosted opaque schemes, after rejecting paths, queries, fragments, credentials, hostless schemes, dot-segment normalization, and backslash path separators. No prefix or scheme wildcard is introduced.

Verification:

  • Blacksmith Testbox tbx_01kx3a3cqcgztce1p3rc9wrqmp / Actions 29014889369: 146/146 focused validator and real Gateway auth tests passed.
  • The real Gateway test configures token auth plus allowedOrigins: ["tauri://localhost"], opens a WebSocket with that Origin header, performs the Gateway connect handshake, and receives hello-ok; sibling cases prove malformed and unlisted origins remain rejected.
  • Fresh autoreview: clean after two review-discovered canonicalization bypasses (dot segments and backslashes) were fixed and regression-tested.
  • Exact-head GitHub CI 29015196396, Workflow Sanity 29015196381, CodeQL 29015196424, CodeQL Critical Quality 29015196537, OpenGrep 29015196574, and iOS Periphery 29015196447 passed.
  • git diff --check and repository formatting passed.

The PR body now documents the precise grant boundary and user impact. Contributor credit is preserved in the commit trailer.

@steipete

steipete commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Merged via squash.

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

Labels

gateway Gateway runtime merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. 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. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: S status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Origin validation fails for custom URL schemes (tauri://, electron://)

4 participants