Research: Secure Architecture for Hero Browser inside HeroOS (Iframe vs Proxy) #2

Open
opened 2026-02-04 11:50:56 +00:00 by mahmoud · 3 comments
Owner

Context

HeroOS is a browser-based OS built using Rust + Dioxus, where applications are integrated via WASM.

Current apps include:

  • LiveKit Rooms (meetings)

  • Editors (Vim-like)(TODO)

  • AI Chat

  • Hero Business (employee/dashboard management)

  • Hero Browser (embedded browser app)

Hero Browser is currently integrated into HeroOS using an iframe

Problem Statement

Using a native browser embedded via iframe introduces security, UX, and functional limitations, including but not limited to:

  1. URL navigation limitations
  • Typing google.com does not reliably navigate to the final destination due to iframe restrictions (sandboxing, mixed content, CSP, X-Frame-Options).
  1. Security leakage risks
  • Parent (HeroOS) and iframe (browser) boundary can be abused if misconfigured.
  • Potential exposure of cookies, storage, or postMessage misuse.
  1. Blocked websites
  • Many modern websites explicitly prevent iframe embedding (X-Frame-Options: DENY or SAMEORIGIN).
  1. Limited control
  • Hard to intercept requests, headers, auth, or apply OS-level policies.

This makes the current iframe-based approach non-viable for a production-grade “OS browser” experience.

Research Goal

Investigate alternative architectures for implementing Hero Browser inside HeroOS that:

  • Avoid iframe security & navigation limitations
  • Allow full URL navigation (e.g. google.comhttps://www.google.com)
  • Maintain isolation between HeroOS and external websites
  • Are compatible with a WASM-first, browser-based OS

Proposed Proxy-Based Flow (High-Level)

flowchart LR
    U[User] -->|Interact with| HO[HeroOS UI]
    HO -->|Open Hero Browser| HB["Hero Browser App WASM"]
    U -->|Type URL| HB
    HB -->|Request| HP["Hero Proxy Layer"]
    HP -->|Fetch| EXT["External Website"]
    EXT -->|HTML/CSS/JS| HP
    HP -->|Rewrite & Sanitize| HB
    HB -->|Render| HO
### Context HeroOS is a browser-based OS built using Rust + Dioxus, where applications are integrated via WASM. #### Current apps include: - LiveKit Rooms (meetings) - Editors (Vim-like)(TODO) - AI Chat - Hero Business (employee/dashboard management) - Hero Browser (embedded browser app) > Hero Browser is currently integrated into HeroOS using an iframe #### Problem Statement Using a native browser embedded via `iframe` introduces security, UX, and functional limitations, including but not limited to: 1. URL navigation limitations - Typing `google.com` does not reliably navigate to the final destination due to iframe restrictions (sandboxing, mixed content, CSP, X-Frame-Options). 2. Security leakage risks - Parent (HeroOS) and iframe (browser) boundary can be abused if misconfigured. - Potential exposure of cookies, storage, or postMessage misuse. 3. Blocked websites - Many modern websites explicitly prevent iframe embedding (`X-Frame-Options: DENY or SAMEORIGIN`). 4. Limited control - Hard to intercept requests, headers, auth, or apply OS-level policies. This makes the current iframe-based approach non-viable for a production-grade “OS browser” experience. #### Research Goal Investigate alternative architectures for implementing Hero Browser inside HeroOS that: - Avoid iframe security & navigation limitations - Allow full URL navigation (e.g. `google.com` → `https://www.google.com`) - Maintain isolation between HeroOS and external websites - Are compatible with a WASM-first, browser-based OS #### Proposed Proxy-Based Flow (High-Level) ```mermaid flowchart LR U[User] -->|Interact with| HO[HeroOS UI] HO -->|Open Hero Browser| HB["Hero Browser App WASM"] U -->|Type URL| HB HB -->|Request| HP["Hero Proxy Layer"] HP -->|Fetch| EXT["External Website"] EXT -->|HTML/CSS/JS| HP HP -->|Rewrite & Sanitize| HB HB -->|Render| HO ```
mahmoud self-assigned this 2026-02-04 11:51:50 +00:00
Author
Owner

Research Summary: Hero Browser Architecture Options

Based on my research, here are the main approaches for implementing a browser-within-browser that avoids iframe limitations:

The Core Problem

The iframe approach fails because:

  1. X-Frame-Options / CSP: Most sites block iframe embedding (X-Frame-Options: DENY)
  2. Same-Origin Policy: Can't access iframe content from parent
  3. Navigation restrictions: Links inside iframe can't be controlled
  4. Mixed content: HTTPS pages can't embed HTTP content

Three Viable Architecture Approaches

1. Pixel Streaming (Remote Browser Isolation)

How it works:

  • Run a headless browser (Chrome/Firefox) on the server
  • Stream the rendered output as video/images to the client
  • Forward user input (mouse, keyboard) back to server

Pros:

  • 100% website compatibility
  • Complete isolation - no code reaches client
  • Works with any site including Google, banking sites

Cons:

  • High bandwidth (3-5 Mbps continuous)
  • Latency-sensitive
  • Server-heavy (one browser instance per session)
  • Text can appear fuzzy on HiDPI displays

Used by: Cloudflare Browser Isolation, enterprise RBI solutions


2. DOM Reconstruction with Proxy (Current hero_os approach, needs improvement)

How it works:

  • Server fetches HTML from target site
  • Rewrite all URLs to go through proxy
  • Strip/sanitize dangerous scripts
  • Send sanitized HTML to client for native rendering

Pros:

  • Low bandwidth (~500KB per page)
  • Native text rendering (crisp fonts)
  • Good for document/content sites

Cons:

  • Complex JavaScript sites break (React, Vue, SPAs)
  • Requires sophisticated URL rewriting
  • JavaScript rewriting is extremely difficult
  • Many edge cases and "location escapes"

The JS Rewriting Challenge (from Titanium Network docs):

"JS rewriting is the biggest hurdle when making a proxy... You can't monkeypatch location objects since they are non-configurable properties."


3. Service Worker Interception Proxy (Ultraviolet/Scramjet approach)

How it works:

  • Register a Service Worker that intercepts ALL fetch requests
  • Rewrite URLs on-the-fly in the browser
  • Use a "Bare Server" backend to actually fetch content
  • Client-side JavaScript AST rewriting

Architecture:

User → Service Worker → Bare Server → Target Website
                ↓
        JS/HTML Rewriting
                ↓
        Rendered in browser

Pros:

  • Runs mostly client-side (low server load)
  • Good compatibility with modern sites
  • Active open-source community (Ultraviolet, Scramjet)

Cons:

  • Still can't handle all JS edge cases
  • Requires complex rewriting infrastructure
  • Service Worker scope limitations

Key Insight from Scramjet:

"Scramjet uses byte span rewriting to achieve speed... You may also use direct Rust libraries and WASM Bindgen."


Given that HeroOS is WASM/Dioxus-based, I recommend a hybrid approach:

Phase 1: Enhanced DOM Reconstruction (Immediate)

Improve the current proxy to handle:

  • Better URL rewriting (all attributes, not just src/href)
  • CSS url() rewriting
  • Basic JS rewriting for location, document.URL
  • Strip X-Frame-Options and CSP headers server-side

Phase 2: Service Worker Integration (Medium-term)

Add a Service Worker layer that:

  • Intercepts resource requests from rendered content
  • Handles dynamic JavaScript navigation
  • Works alongside the server proxy

Phase 3: Pixel Streaming Fallback (Long-term)

For sites that can't be proxied:

  • Detect when DOM reconstruction fails
  • Fall back to headless browser + pixel streaming
  • Use Network Vector Rendering (Skia draw commands) for efficiency

Key Technical Requirements

  1. Server-side proxy must:

    • Fetch pages with proper User-Agent
    • Handle cookies/sessions per browser session
    • Rewrite ALL URLs (HTML, CSS, JS)
    • Strip security headers (X-Frame-Options, CSP)
    • Handle redirects transparently
  2. Client-side must:

    • Intercept link clicks before navigation
    • Rewrite window.location access in JS
    • Handle form submissions through proxy
    • Maintain history state
  3. What NOT to render in iframe:

    • Render sanitized HTML directly in a Dioxus component using dangerous_inner_html
    • Or use a sandboxed iframe with srcdoc (current approach) but with better content sanitization

Sources

## Research Summary: Hero Browser Architecture Options Based on my research, here are the main approaches for implementing a browser-within-browser that avoids iframe limitations: ### The Core Problem The iframe approach fails because: 1. **X-Frame-Options / CSP**: Most sites block iframe embedding (`X-Frame-Options: DENY`) 2. **Same-Origin Policy**: Can't access iframe content from parent 3. **Navigation restrictions**: Links inside iframe can't be controlled 4. **Mixed content**: HTTPS pages can't embed HTTP content --- ## Three Viable Architecture Approaches ### 1. **Pixel Streaming (Remote Browser Isolation)** **How it works:** - Run a headless browser (Chrome/Firefox) on the server - Stream the rendered output as video/images to the client - Forward user input (mouse, keyboard) back to server **Pros:** - 100% website compatibility - Complete isolation - no code reaches client - Works with any site including Google, banking sites **Cons:** - High bandwidth (3-5 Mbps continuous) - Latency-sensitive - Server-heavy (one browser instance per session) - Text can appear fuzzy on HiDPI displays **Used by:** [Cloudflare Browser Isolation](https://blog.cloudflare.com/cloudflare-and-remote-browser-isolation/), enterprise RBI solutions --- ### 2. **DOM Reconstruction with Proxy (Current hero_os approach, needs improvement)** **How it works:** - Server fetches HTML from target site - Rewrite all URLs to go through proxy - Strip/sanitize dangerous scripts - Send sanitized HTML to client for native rendering **Pros:** - Low bandwidth (~500KB per page) - Native text rendering (crisp fonts) - Good for document/content sites **Cons:** - Complex JavaScript sites break (React, Vue, SPAs) - Requires sophisticated URL rewriting - JavaScript rewriting is extremely difficult - Many edge cases and "location escapes" **The JS Rewriting Challenge** (from [Titanium Network docs](https://docs.titaniumnetwork.org/guides/interception-proxy-guide/rewriting)): > "JS rewriting is the biggest hurdle when making a proxy... You can't monkeypatch location objects since they are non-configurable properties." --- ### 3. **Service Worker Interception Proxy (Ultraviolet/Scramjet approach)** **How it works:** - Register a Service Worker that intercepts ALL fetch requests - Rewrite URLs on-the-fly in the browser - Use a "Bare Server" backend to actually fetch content - Client-side JavaScript AST rewriting **Architecture:** ``` User → Service Worker → Bare Server → Target Website ↓ JS/HTML Rewriting ↓ Rendered in browser ``` **Pros:** - Runs mostly client-side (low server load) - Good compatibility with modern sites - Active open-source community ([Ultraviolet](https://github.com/titaniumnetwork-dev/Ultraviolet), [Scramjet](https://docs.titaniumnetwork.org/proxies/scramjet/)) **Cons:** - Still can't handle all JS edge cases - Requires complex rewriting infrastructure - Service Worker scope limitations **Key Insight from [Scramjet](https://docs.titaniumnetwork.org/proxies/scramjet/):** > "Scramjet uses byte span rewriting to achieve speed... You may also use direct Rust libraries and WASM Bindgen." --- ## Recommended Approach for HeroOS Given that HeroOS is WASM/Dioxus-based, I recommend a **hybrid approach**: ### Phase 1: Enhanced DOM Reconstruction (Immediate) Improve the current proxy to handle: - Better URL rewriting (all attributes, not just `src`/`href`) - CSS `url()` rewriting - Basic JS rewriting for `location`, `document.URL` - Strip X-Frame-Options and CSP headers server-side ### Phase 2: Service Worker Integration (Medium-term) Add a Service Worker layer that: - Intercepts resource requests from rendered content - Handles dynamic JavaScript navigation - Works alongside the server proxy ### Phase 3: Pixel Streaming Fallback (Long-term) For sites that can't be proxied: - Detect when DOM reconstruction fails - Fall back to headless browser + pixel streaming - Use [Network Vector Rendering](https://www.menlosecurity.com/blog/the-mobile-isolation-era-begins-smart-dom) (Skia draw commands) for efficiency --- ## Key Technical Requirements 1. **Server-side proxy must:** - Fetch pages with proper User-Agent - Handle cookies/sessions per browser session - Rewrite ALL URLs (HTML, CSS, JS) - Strip security headers (X-Frame-Options, CSP) - Handle redirects transparently 2. **Client-side must:** - Intercept link clicks before navigation - Rewrite `window.location` access in JS - Handle form submissions through proxy - Maintain history state 3. **What NOT to render in iframe:** - Render sanitized HTML directly in a Dioxus component using `dangerous_inner_html` - Or use a sandboxed iframe with `srcdoc` (current approach) but with better content sanitization --- ## Sources - [Surfly - Embedding Non-Embeddable Content](https://www.surfly.com/blog/embedding-non-embeddable-content) - [Ultraviolet Proxy - GitHub](https://github.com/titaniumnetwork-dev/Ultraviolet) - [Titanium Network - Rewriting Guide](https://docs.titaniumnetwork.org/guides/interception-proxy-guide/rewriting) - [Scramjet Proxy Documentation](https://docs.titaniumnetwork.org/proxies/scramjet/) - [Cloudflare Browser Isolation](https://blog.cloudflare.com/cloudflare-and-remote-browser-isolation/) - [Menlo Security - Smart DOM](https://www.menlosecurity.com/blog/the-mobile-isolation-era-begins-smart-dom) - [MDN - Service Worker Fetch Event](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerGlobalScope/fetch_event) - [BikiniProxy - HTML/JS Rewriting](https://github.com/Spirals-Team/bikiniproxy)
Owner

we only support basic websites for now, lets disable browser for now

we only support basic websites for now, lets disable browser for now
Author
Owner

Added to hero_wasmos backlog column lhumina_code/hero_wasmos#1

Added to hero_wasmos `backlog column` https://forge.ourworld.tf/lhumina_code/hero_wasmos/issues/1
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_os#2
No description provided.