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

Open
opened 2026-02-04 11:50:56 +00:00 by mahmoud · 2 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
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.