@dynamic-labs/iframe-setup 5.0.0-rc.0 → 5.0.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,76 @@
1
1
 
2
- ## [5.0.0-rc.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.91.6...v5.0.0-rc.0) (2026-07-05)
2
+ ## [5.0.0-rc.1](https://github.com/dynamic-labs/dynamic-auth/compare/v5.0.0-rc.0...v5.0.0-rc.1) (2026-07-17)
3
+
4
+
5
+ ### ⚠ BREAKING CHANGES
6
+
7
+ * move legacy embedded wallet to waas upgrade flow to new legacy-embedded-wallet-migration package (#11841)
8
+ * drop default injection of legacy embedded wallet connectors (#11833)
9
+ * remove legacy embedded wallet support (#11979)
10
+ * throw when legacy embedded wallet is detected without migration provider (#11855)
11
+ * remove deprecated eclipse package (#11831)
12
+ * remove deprecated functions and props (#11832)
13
+
14
+
15
+ ### [4.92.4](https://github.com/dynamic-labs/dynamic-auth/compare/v4.92.3...v4.92.4) (2026-07-16)
16
+
17
+
18
+ ### Features
19
+
20
+ * **bitcoin:** per-network address switching and dust-limit send validation [v4] ([#11970](https://github.com/dynamic-labs/dynamic-auth/issues/11970)) ([76a4a9a](https://github.com/dynamic-labs/dynamic-auth/commit/76a4a9a5025d78798ebd1beffe6c0af59d2d029a)), closes [#11896](https://github.com/dynamic-labs/dynamic-auth/issues/11896) [#11800](https://github.com/dynamic-labs/dynamic-auth/issues/11800)
21
+ * **midnight:** per-network addresses in deposit and wallet info views [v4] ([#11949](https://github.com/dynamic-labs/dynamic-auth/issues/11949)) ([978446a](https://github.com/dynamic-labs/dynamic-auth/commit/978446aca8546eb038ba9ed3be0503d10594ee15))
22
+ * **midnight:** resolve wallet address per selected network [v4] ([#11948](https://github.com/dynamic-labs/dynamic-auth/issues/11948)) ([d6f858c](https://github.com/dynamic-labs/dynamic-auth/commit/d6f858c5e35defda7ed73cf97b3fdbe5ed9d131d))
23
+ * set useMetamaskSdk to true by default ([#11926](https://github.com/dynamic-labs/dynamic-auth/issues/11926)) ([75b5a4a](https://github.com/dynamic-labs/dynamic-auth/commit/75b5a4a0fe8b1a375afce145c0b8bdc3ce761117))
24
+
25
+
26
+ ### Bug Fixes
27
+
28
+ * **midnight:** align per-network code with the final main iteration [v4] ([#11971](https://github.com/dynamic-labs/dynamic-auth/issues/11971)) ([3ef3ba8](https://github.com/dynamic-labs/dynamic-auth/commit/3ef3ba8c090dfd9e4286b4e51bf350ea5e6feac7))
29
+ * settle social sign-in when captcha is backed out or oauth popup never responds (v4) ([#11956](https://github.com/dynamic-labs/dynamic-auth/issues/11956)) ([ad49477](https://github.com/dynamic-labs/dynamic-auth/commit/ad49477f2acf61a154bb79cbe26b24f803cdb0e2))
30
+ * validate that private key is not empty before upgrading to WaaS ([#11952](https://github.com/dynamic-labs/dynamic-auth/issues/11952)) ([21dfb83](https://github.com/dynamic-labs/dynamic-auth/commit/21dfb83cb29e42b335bc94a0cdd2062cf14a262a))
31
+
32
+ ### [4.92.3](https://github.com/dynamic-labs/dynamic-auth/compare/v4.92.2...v4.92.3) (2026-07-10)
33
+
34
+
35
+ ### Bug Fixes
36
+
37
+ * **sdk-react-core:** fix deterministic 'Wallet not found' crash in embedded wallet export (v4) ([#11906](https://github.com/dynamic-labs/dynamic-auth/issues/11906)) ([913ef23](https://github.com/dynamic-labs/dynamic-auth/commit/913ef236b26245488e1cd5db7e874601b65ff0a2)), closes [#11905](https://github.com/dynamic-labs/dynamic-auth/issues/11905) [#11729](https://github.com/dynamic-labs/dynamic-auth/issues/11729)
38
+
39
+ ### [4.92.2](https://github.com/dynamic-labs/dynamic-auth/compare/v4.92.1...v4.92.2) (2026-07-09)
40
+
41
+
42
+ ### Bug Fixes
43
+
44
+ * engage captcha during step-up OTP re-auth ([#11879](https://github.com/dynamic-labs/dynamic-auth/issues/11879)) ([585460a](https://github.com/dynamic-labs/dynamic-auth/commit/585460a8976803a8ed0aad16a4a00047bd6c115a))
45
+ * **waas:** gate v1 wallet upgrade on recovery for email-only wallets ([#11897](https://github.com/dynamic-labs/dynamic-auth/issues/11897)) ([5a6f0c6](https://github.com/dynamic-labs/dynamic-auth/commit/5a6f0c6bf3120e59cf502004d09fae56f193e977))
46
+
47
+ ### [4.92.1](https://github.com/dynamic-labs/dynamic-auth/compare/v4.92.0...v4.92.1) (2026-07-09)
48
+
49
+
50
+ ### Bug Fixes
51
+
52
+ * **ethereum:** fire in-app-browser redirect on sign for injected EVM wallets that use in-app-browser experience ([#11888](https://github.com/dynamic-labs/dynamic-auth/issues/11888)) ([5116d91](https://github.com/dynamic-labs/dynamic-auth/commit/5116d91ab2c71000a490d72c5d278549d4d8ae9a))
53
+ * **sdk-react-core:** show clear message for Phantom redirect signing failures (v4 backport) ([#11886](https://github.com/dynamic-labs/dynamic-auth/issues/11886)) ([60ac897](https://github.com/dynamic-labs/dynamic-auth/commit/60ac897ba81f7758ccd7a05f97b619785e1f50a7))
54
+ * **social:** use redirect strategy for step-up OAuth on mobile [V4 backport] ([#11881](https://github.com/dynamic-labs/dynamic-auth/issues/11881)) ([42a202e](https://github.com/dynamic-labs/dynamic-auth/commit/42a202e6255de8db73df02eff37c0b10b24fef1a))
55
+ * **solana:** fire in-app-browser redirect on sign and wallet switch ([#11871](https://github.com/dynamic-labs/dynamic-auth/issues/11871)) ([4e2d6b7](https://github.com/dynamic-labs/dynamic-auth/commit/4e2d6b7ac8fdef5bf7c62b8a726ecaef1c6210ec))
56
+ * **solana:** resolve Phantom/Backpack provider collision and Backpack >=0.10.x connect hangs ([#11856](https://github.com/dynamic-labs/dynamic-auth/issues/11856)) ([#11882](https://github.com/dynamic-labs/dynamic-auth/issues/11882)) ([5784aff](https://github.com/dynamic-labs/dynamic-auth/commit/5784aff9641bbc85445fb466f3ab1d6a14331e73))
57
+
58
+ ## [4.92.0](https://github.com/dynamic-labs/dynamic-auth/compare/v4.91.6...v4.92.0) (2026-07-08)
59
+
60
+
61
+ ### Features
62
+
63
+ * **captcha:** add Cloudflare Turnstile provider support alongside hCaptcha (v4) ([#11798](https://github.com/dynamic-labs/dynamic-auth/issues/11798)) ([114c770](https://github.com/dynamic-labs/dynamic-auth/commit/114c7702e900d8dedeebe7be867de35d11a93f31))
64
+
65
+
66
+ ### Bug Fixes
67
+
68
+ * **ethereum-aa:** resolve kernel client config per wallet (v4) ([#11870](https://github.com/dynamic-labs/dynamic-auth/issues/11870)) ([1b66d79](https://github.com/dynamic-labs/dynamic-auth/commit/1b66d79b4a32b4b6de433b7536bc46e6719224c6))
69
+ * **iframe-setup:** block dangerous URL schemes and verify sender in OPEN_URL ([#11819](https://github.com/dynamic-labs/dynamic-auth/issues/11819)) ([329b27e](https://github.com/dynamic-labs/dynamic-auth/commit/329b27e9fac825916ab227ec8cf93dc343898923))
70
+ * improve social OAuth error messages ([#11837](https://github.com/dynamic-labs/dynamic-auth/issues/11837)) ([8e57c06](https://github.com/dynamic-labs/dynamic-auth/commit/8e57c067c5a89111a32a12fb82e190cf6c46ad67))
71
+ * **react-native-extension:** reject path traversal in downloadFile fileName ([#11816](https://github.com/dynamic-labs/dynamic-auth/issues/11816)) ([9367a56](https://github.com/dynamic-labs/dynamic-auth/commit/9367a56b6daa853d7f7e7f5534261bc68825b239))
72
+ * **sdk-react-core:** display exactly the bytes signed in personal_sign preview ([#11818](https://github.com/dynamic-labs/dynamic-auth/issues/11818)) ([30b9382](https://github.com/dynamic-labs/dynamic-auth/commit/30b93829122f00060cb484aef09a03294c03f651))
73
+
3
74
 
4
75
  ### [4.91.6](https://github.com/dynamic-labs/dynamic-auth/compare/v4.91.5...v4.91.6) (2026-07-03)
5
76
 
package/README.md CHANGED
@@ -146,12 +146,20 @@ export const setupIframe = (
146
146
  ): VoidFunction => {
147
147
  if (typeof window === 'undefined') return () => {};
148
148
 
149
- const messageHandler = createMessageHandler<IFRAME_EVENTS>(window, origin);
149
+ const messageHandler = createMessageHandler<IFRAME_EVENTS>(
150
+ window,
151
+ origin,
152
+ iframe,
153
+ );
150
154
  const messageSender = createMessageSender<IFRAME_EVENTS>(iframe);
151
155
 
152
156
  // Add event listener to handle deeplink
153
157
  const setupOpenUrlHandler = () =>
154
158
  messageHandler('OPEN_URL', ({ url, target = 'self', features }) => {
159
+ // This navigates the host top window, so never honor a URL whose scheme
160
+ // can execute script in the host origin (iframe->host XSS).
161
+ if (hasDangerousScheme(url)) return;
162
+
155
163
  if (target === 'blank') {
156
164
  window.open(url, '_blank', features);
157
165
  } else {
@@ -220,6 +228,45 @@ export const setupIframe = (
220
228
 
221
229
  // Utils
222
230
 
231
+ /**
232
+ * URL schemes that can execute script in the host origin. Navigating the host
233
+ * top window to any of these turns an OPEN_URL message into arbitrary code
234
+ * execution in the integrator's origin, so they are blocked.
235
+ *
236
+ * A deny-list (rather than an http/https allow-list) is used deliberately:
237
+ * wallet flows legitimately open custom-scheme deep links, and allow-listing
238
+ * http(s) would break them.
239
+ */
240
+ const DANGEROUS_SCHEMES = [
241
+ 'javascript:',
242
+ 'data:',
243
+ 'blob:',
244
+ 'vbscript:',
245
+ 'file:',
246
+ ];
247
+
248
+ /**
249
+ * Leading characters the browser ignores when resolving a URL scheme: spaces,
250
+ * tabs, newlines and other C0 control chars (U+0000–U+0020). Stripping them
251
+ * defeats obfuscation such as "\tjavascript:alert(1)".
252
+ */
253
+ // eslint-disable-next-line no-control-regex
254
+ const LEADING_IGNORED_CHARS = /^[\u0000-\u0020]+/;
255
+
256
+ /**
257
+ * Returns true when the URL begins with a script-executing scheme.
258
+ *
259
+ * Non-string input is treated as dangerous, leading ignored chars are stripped
260
+ * first, and the comparison is case-insensitive ("JavaScript:" is blocked).
261
+ */
262
+ const hasDangerousScheme = (url: unknown): boolean => {
263
+ if (typeof url !== 'string') return true;
264
+
265
+ const normalized = url.replace(LEADING_IGNORED_CHARS, '').toLowerCase();
266
+
267
+ return DANGEROUS_SCHEMES.some((scheme) => normalized.startsWith(scheme));
268
+ };
269
+
223
270
  /**
224
271
  * Custom event dispatched when the parent URL changes via the History API.
225
272
  * Used instead of re-patching history per setupIframe call so that multiple
@@ -262,7 +309,11 @@ const patchHistoryOnce = (): void => {
262
309
  * Create a message handler for the iframe
263
310
  */
264
311
  const createMessageHandler =
265
- <T extends Record<string, MESSAGE_HANDLER>>(window: Window, origin: string) =>
312
+ <T extends Record<string, MESSAGE_HANDLER>>(
313
+ window: Window,
314
+ origin: string,
315
+ iframe: HTMLIFrameElement,
316
+ ) =>
266
317
  <EVENT_NAME extends Extract<keyof T, string>>(
267
318
  eventName: EVENT_NAME,
268
319
  handler: T[EVENT_NAME],
@@ -270,6 +321,10 @@ const createMessageHandler =
270
321
  const messageHandler = (event: MessageEvent) => {
271
322
  if (event.origin !== origin) return;
272
323
 
324
+ // Only trust messages coming from this iframe's own window. Checking the
325
+ // origin alone lets any frame/tab at the SDK-iframe origin forge events.
326
+ if (event.source !== iframe.contentWindow) return;
327
+
273
328
  const { eventName: incomingEventName, args } = event.data;
274
329
 
275
330
  if (eventName === incomingEventName) {
package/package.cjs CHANGED
@@ -3,6 +3,6 @@
3
3
 
4
4
  Object.defineProperty(exports, '__esModule', { value: true });
5
5
 
6
- var version = "5.0.0-rc.0";
6
+ var version = "5.0.0-rc.1";
7
7
 
8
8
  exports.version = version;
package/package.js CHANGED
@@ -1,4 +1,4 @@
1
1
  'use client'
2
- var version = "5.0.0-rc.0";
2
+ var version = "5.0.0-rc.1";
3
3
 
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dynamic-labs/iframe-setup",
3
- "version": "5.0.0-rc.0",
3
+ "version": "5.0.0-rc.1",
4
4
  "description": "Collection of utilities to use the Dynamic SDK in an iframe",
5
5
  "author": "Dynamic Labs, Inc.",
6
6
  "license": "MIT",
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "homepage": "https://www.dynamic.xyz/",
20
20
  "dependencies": {
21
- "@dynamic-labs/assert-package-version": "5.0.0-rc.0"
21
+ "@dynamic-labs/assert-package-version": "5.0.0-rc.1"
22
22
  },
23
23
  "peerDependencies": {}
24
24
  }
@@ -22,10 +22,14 @@ Object.defineProperty(exports, '__esModule', { value: true });
22
22
  const setupIframe = (iframe, origin) => {
23
23
  if (typeof window === 'undefined')
24
24
  return () => { };
25
- const messageHandler = createMessageHandler(window, origin);
25
+ const messageHandler = createMessageHandler(window, origin, iframe);
26
26
  const messageSender = createMessageSender(iframe);
27
27
  // Add event listener to handle deeplink
28
28
  const setupOpenUrlHandler = () => messageHandler('OPEN_URL', ({ url, target = 'self', features }) => {
29
+ // This navigates the host top window, so never honor a URL whose scheme
30
+ // can execute script in the host origin (iframe->host XSS).
31
+ if (hasDangerousScheme(url))
32
+ return;
29
33
  if (target === 'blank') {
30
34
  window.open(url, '_blank', features);
31
35
  }
@@ -82,6 +86,41 @@ const setupIframe = (iframe, origin) => {
82
86
  return () => cleanupHandlers.forEach((offHandler) => offHandler());
83
87
  };
84
88
  // Utils
89
+ /**
90
+ * URL schemes that can execute script in the host origin. Navigating the host
91
+ * top window to any of these turns an OPEN_URL message into arbitrary code
92
+ * execution in the integrator's origin, so they are blocked.
93
+ *
94
+ * A deny-list (rather than an http/https allow-list) is used deliberately:
95
+ * wallet flows legitimately open custom-scheme deep links, and allow-listing
96
+ * http(s) would break them.
97
+ */
98
+ const DANGEROUS_SCHEMES = [
99
+ 'javascript:',
100
+ 'data:',
101
+ 'blob:',
102
+ 'vbscript:',
103
+ 'file:',
104
+ ];
105
+ /**
106
+ * Leading characters the browser ignores when resolving a URL scheme: spaces,
107
+ * tabs, newlines and other C0 control chars (U+0000–U+0020). Stripping them
108
+ * defeats obfuscation such as "\tjavascript:alert(1)".
109
+ */
110
+ // eslint-disable-next-line no-control-regex
111
+ const LEADING_IGNORED_CHARS = /^[\u0000-\u0020]+/;
112
+ /**
113
+ * Returns true when the URL begins with a script-executing scheme.
114
+ *
115
+ * Non-string input is treated as dangerous, leading ignored chars are stripped
116
+ * first, and the comparison is case-insensitive ("JavaScript:" is blocked).
117
+ */
118
+ const hasDangerousScheme = (url) => {
119
+ if (typeof url !== 'string')
120
+ return true;
121
+ const normalized = url.replace(LEADING_IGNORED_CHARS, '').toLowerCase();
122
+ return DANGEROUS_SCHEMES.some((scheme) => normalized.startsWith(scheme));
123
+ };
85
124
  /**
86
125
  * Custom event dispatched when the parent URL changes via the History API.
87
126
  * Used instead of re-patching history per setupIframe call so that multiple
@@ -117,10 +156,14 @@ const patchHistoryOnce = () => {
117
156
  /**
118
157
  * Create a message handler for the iframe
119
158
  */
120
- const createMessageHandler = (window, origin) => (eventName, handler) => {
159
+ const createMessageHandler = (window, origin, iframe) => (eventName, handler) => {
121
160
  const messageHandler = (event) => {
122
161
  if (event.origin !== origin)
123
162
  return;
163
+ // Only trust messages coming from this iframe's own window. Checking the
164
+ // origin alone lets any frame/tab at the SDK-iframe origin forge events.
165
+ if (event.source !== iframe.contentWindow)
166
+ return;
124
167
  const { eventName: incomingEventName, args } = event.data;
125
168
  if (eventName === incomingEventName) {
126
169
  handler(...args);
@@ -18,10 +18,14 @@
18
18
  const setupIframe = (iframe, origin) => {
19
19
  if (typeof window === 'undefined')
20
20
  return () => { };
21
- const messageHandler = createMessageHandler(window, origin);
21
+ const messageHandler = createMessageHandler(window, origin, iframe);
22
22
  const messageSender = createMessageSender(iframe);
23
23
  // Add event listener to handle deeplink
24
24
  const setupOpenUrlHandler = () => messageHandler('OPEN_URL', ({ url, target = 'self', features }) => {
25
+ // This navigates the host top window, so never honor a URL whose scheme
26
+ // can execute script in the host origin (iframe->host XSS).
27
+ if (hasDangerousScheme(url))
28
+ return;
25
29
  if (target === 'blank') {
26
30
  window.open(url, '_blank', features);
27
31
  }
@@ -78,6 +82,41 @@ const setupIframe = (iframe, origin) => {
78
82
  return () => cleanupHandlers.forEach((offHandler) => offHandler());
79
83
  };
80
84
  // Utils
85
+ /**
86
+ * URL schemes that can execute script in the host origin. Navigating the host
87
+ * top window to any of these turns an OPEN_URL message into arbitrary code
88
+ * execution in the integrator's origin, so they are blocked.
89
+ *
90
+ * A deny-list (rather than an http/https allow-list) is used deliberately:
91
+ * wallet flows legitimately open custom-scheme deep links, and allow-listing
92
+ * http(s) would break them.
93
+ */
94
+ const DANGEROUS_SCHEMES = [
95
+ 'javascript:',
96
+ 'data:',
97
+ 'blob:',
98
+ 'vbscript:',
99
+ 'file:',
100
+ ];
101
+ /**
102
+ * Leading characters the browser ignores when resolving a URL scheme: spaces,
103
+ * tabs, newlines and other C0 control chars (U+0000–U+0020). Stripping them
104
+ * defeats obfuscation such as "\tjavascript:alert(1)".
105
+ */
106
+ // eslint-disable-next-line no-control-regex
107
+ const LEADING_IGNORED_CHARS = /^[\u0000-\u0020]+/;
108
+ /**
109
+ * Returns true when the URL begins with a script-executing scheme.
110
+ *
111
+ * Non-string input is treated as dangerous, leading ignored chars are stripped
112
+ * first, and the comparison is case-insensitive ("JavaScript:" is blocked).
113
+ */
114
+ const hasDangerousScheme = (url) => {
115
+ if (typeof url !== 'string')
116
+ return true;
117
+ const normalized = url.replace(LEADING_IGNORED_CHARS, '').toLowerCase();
118
+ return DANGEROUS_SCHEMES.some((scheme) => normalized.startsWith(scheme));
119
+ };
81
120
  /**
82
121
  * Custom event dispatched when the parent URL changes via the History API.
83
122
  * Used instead of re-patching history per setupIframe call so that multiple
@@ -113,10 +152,14 @@ const patchHistoryOnce = () => {
113
152
  /**
114
153
  * Create a message handler for the iframe
115
154
  */
116
- const createMessageHandler = (window, origin) => (eventName, handler) => {
155
+ const createMessageHandler = (window, origin, iframe) => (eventName, handler) => {
117
156
  const messageHandler = (event) => {
118
157
  if (event.origin !== origin)
119
158
  return;
159
+ // Only trust messages coming from this iframe's own window. Checking the
160
+ // origin alone lets any frame/tab at the SDK-iframe origin forge events.
161
+ if (event.source !== iframe.contentWindow)
162
+ return;
120
163
  const { eventName: incomingEventName, args } = event.data;
121
164
  if (eventName === incomingEventName) {
122
165
  handler(...args);