Repository navigation
fix(react-native-ui): accept offramp events only from the main frame (OFFRAMP-731) - #2293
Open
AngelPaella wants to merge 6 commits into
Conversation
…in frame (OFFRAMP-731)
…navigation and stamp only the own session (OFFRAMP-731)
…rchParams and warn when a load is not stamped (OFFRAMP-731)
🦋 Changeset detectedLatest commit: 8a54f2e The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
…load start (OFFRAMP-731)
AngelPaella
marked this pull request as ready for review
November 6, 2026 18:40
Contributor
[Medium impact] The PR appears safe to merge within its stated interim scope. Reviews (1) · Last reviewed commit: "fix(react-native-ui): reset offramp wall..." · Reviewed by Greptile |
…t nonce (OFFRAMP-731)
…offramp main-frame check
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Part of OFFRAMP-731. The issue stays open until every host ships.
Page side: Paella-Labs/crossbit-main#34023, which stamps the nonce. Until it ships, this gate accepts the page's events unchanged.
On Android, react-native-webview gives
window.ReactNativeWebView.postMessageto every frame, and the message'surlis either the sender's origin (WebMessageListener) or the main page's URL (legacyaddJavascriptInterface). SoisOfframpPagecan't tell which frame posted. The offramp page hosts a cross-origin frame (Persona's capture widget during KYC), and on the legacy path its messages pass the check. A frame could then sendcrypto:send-transactionorcrypto:sign-messageand have the host's payer sign, or send a fakeofframp:completed.The first version of this PR injected a stamping wrapper into the main frame with
injectJavaScript. It now uses a nonce that the page stamps itself, the same contract as Flutter:react-native-get-random-values, as 32 lowercase hex) and loads<url>#mainFrameNonce=<nonce>. The query doesn't change. A new mount gets a new nonce; rerenders keep it.data.__mainFrameNonceon every event it sends (a crossbit-main change). A cross-origin frame can't read the page's fragment, so it can't stamp.console.warnthat names the event and no reply. This covers all events now, not only wallet requests, so a forgedofframp:completedorofframp:readyis dropped too. The latch lasts for the mount, acrossonLoadStartandonLoad. The page keeps the fragment in its URL, so a reload keeps stamping.ui:height.changedas soon as it renders, long before KYC adds the Persona frame.isOfframpPage. Messages without a stringeventpass as before; no handler takes them.sameSession.ts) is gone. A page the WebView ends up on without this mount's fragment can't stamp, so after the latch its events are dropped.offramp:ready(each new document sends it once), not ononLoadStart, as feat(offramp): payer.signMessage for in-iframe wallet ownership proof (OFFRAMP-664) #2266 already does on web. Before, areplaceStatewhile a signature was pending dropped the wallet's reply, and the page waited 120 s for a transaction or forever for a message signature. This also fixescrypto:send-transactionas it is on main.Stacked on #2266 (OFFRAMP-664), which adds
crypto:sign-message. Flutter: Crossmint/crossmint-flutter-sdk#117.Compatibility:
offramp:readyreset, with one warning per mount and no frame check.What it leaves open, for OFFRAMP-731's contract-level fix:
Test plan
packages/client/ui/react-native,crossmint-embedded-offramp.test.tsx: the WebView loads the route with a 32-char lowercase hex nonce in the fragment and the query unchanged; a new mount gets a new nonce and rerenders keep it; stamped events are accepted and stamped wallet requests answered, with no warning; after a stamped event, unstampedcrypto:send-transaction,crypto:sign-messageandofframp:completedare dropped with one warning that names the event and leaves out the request data, and no reply; a wrong nonce is dropped after the latch and does not trip it; before any stamped event, unstamped events pass with a single warning; another page's message is dropped with no warning; messages without a stringeventpass before and after the latch;datathat is null, a string or a number counts as unstamped without throwing; the latch survivesonLoadStartandonLoad; no script is injected; pending send and sign replies still arrive afteronLoadStart, and afterofframp:readyan old reply is dropped while a new request works.pnpm exec vitest runinpackages/client/ui/react-nativeat 8a54f2e: 8 files, 101 tests passed.tsc --noEmitin the same package: no errors in the touched files. The 5 errors it reports are in test files this PR doesn't touch (with-google-pay,with-device-signer,software-device-signer-key-storage).apps/wallets/expo, react-native-webview 14.0.1, iOS 26.5 simulator, Android 16 emulator) ran on the old injected wrapper, before this rework. The nonce approach has not been device-checked yet. It needs the page change on staging.Package updates
.changeset/offramp-main-frame-only.md: patch for@crossmint/client-sdk-react-native-ui. Its text now describes the fragment nonce and the latch.