Skip to content

fix: fix link handling in example preview iframe sandbox#701

Draft
meshackm wants to merge 2 commits intonexu-io:mainfrom
meshackm:fix/examples-preview-link-handling
Draft

fix: fix link handling in example preview iframe sandbox#701
meshackm wants to merge 2 commits intonexu-io:mainfrom
meshackm:fix/examples-preview-link-handling

Conversation

@meshackm
Copy link
Copy Markdown

@meshackm meshackm commented May 6, 2026

Fix #660 Examples preview iframe link navigation bug

Fixes

  • Added a click interceptor inside the preview iframe
  • Anchor links (href="#", href="#section") scroll correctly within the preview, smooth scrolling works if enabled
  • Links with target="_blank" are safely opened in a new tab, aided by adding the following iframe sandbox options:
    • allow-popups allow-popups-to-escape-sandbox

@lefarcen
Copy link
Copy Markdown
Contributor

lefarcen commented May 6, 2026

Hi @meshackm! 🎉
Thanks for the contribution — this fix for the iframe link navigation is addressing a real usability issue.
I will run a deep review and get back to you within 24h.

Thanks for making open-design better!
— open-design team

@meshackm meshackm marked this pull request as draft May 6, 2026 15:23
Copy link
Copy Markdown
Contributor

@lefarcen lefarcen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @meshackm, thanks for tackling this iframe navigation issue! The approach of adding a click interceptor is sound. However, I found 1 critical bug that would break the entire sandbox shim, plus 2 security/correctness issues:

Critical (P1):

  • apps/web/src/runtime/srcdoc.ts line 165: Invalid JavaScript syntax — href === '; is an unterminated string literal. This breaks the entire injected <script data-od-sandbox-shim>, so the existing localStorage/sessionStorage shims also stop working. Fix to href === ''

Security/correctness (P2):

  • apps/web/src/runtime/srcdoc.ts line 166: Hash-link handler incomplete — doesn't update location.hash, breaking templates using hash state, hashchange events, history/back, CSS :target, named anchors. Suggest: location.hash = href;
  • apps/web/src/runtime/srcdoc.ts line 173: rel attribute doesn't protect window.open(). Always pass 'noopener,noreferrer' as features

Minor (P3):

  • apps/web/src/runtime/srcdoc.ts line 160: e.target may not be Element. Add instanceof check before closest()

Let me know if you need clarification on any of these!

Copy link
Copy Markdown
Contributor

@lefarcen lefarcen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @meshackm! I need to correct my previous review — the P1 I mentioned (unterminated string literal) was a false positive; your code is syntactically correct on line 165. Apologies for the confusion!

However, the 2 security/correctness issues (P2) still remain:

P2 — Hash navigation incomplete:

  • Line 166-170: The hash-link handler prevents default but only calls scrollIntoView(). This doesn't update location.hash, so templates using hash state, hashchange events, history/back, CSS :target, and named anchors will break. Native fragment navigation handles all of this automatically.
  • Fix: Use location.hash = href; instead of manual scrolling, or allow native behavior for valid same-document hashes.

P2 — window.open opener leak:

  • Line 173-178: The logic checks rel === 'noopener noreferrer' (exact string match) and OMITS the noopener,noreferrer features when it matches. This is backwards — the rel attribute does NOT protect a programmatic window.open() call. You must always pass 'noopener,noreferrer' as the third argument.
  • Fix: window.open(href, '_blank', 'noopener,noreferrer') for ALL _blank links, regardless of rel.

P3 — Element check:

  • Line 161: e.target.closest('a[href]') assumes the target is an Element. Click targets can be text nodes, which would throw. Add instanceof Element check first.

Let me know if you need clarification on any of these!

@meshackm
Copy link
Copy Markdown
Author

meshackm commented May 6, 2026

I understand, let me look into it. There was indeed a missing single quote, I added it before your first review.

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

Labels

bug-fix Fixes an existing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Clicking back on the blog-post example "<--Filebase blog" opens an open-design window in that dialog box

2 participants