Sprint 15.1: Dynamic import() in Page-Sandbox ausführen #71

Closed
opened 2026-06-18 16:48:05 +00:00 by Artur · 1 comment
Owner

Dynamic import() — Sandboxed Module Execution

Priorität: Niedrig (~0.5% der Seiten)
Abhängigkeit: Sprint 14 (new Function Sandbox)

Problembeschreibung

import('https://cdn.example.com/module.js') läuft aktuell via Bun's nativem import(), was im globalen Bun-Scope ausgeführt wird. Module haben Zugriff auf Bun, process, Buffer etc. — die Sandbox wird umgangen.

// Aktuell: Module läuft in Bun's globalem Scope
import('https://cdn.example.com/mod.js')
// → Module sieht Bun, process, Buffer (Sicherheitslücke)
// → Module sieht NICHT React, $, etc. (Kompatibilitätsproblem)

Betroffene Seiten: Seltene Fälle von ES Module CDN-Ladern (z.B. import('https://esm.sh/react'))

Architektur-Analyse

Aktueller Ablauf:

Page Code → import(url) → Bun's native Module Loader
                          → Module läuft in globalem Scope
                          → Zugriff auf Bun APIs (escape)
                          → Kein Zugriff auf window.React, $ (broken)

Gewünschter Ablauf:

Page Code → import(url) → Unser intercepter Module Loader
                          → Code via with(_win)-Realm evaluieren
                          → Module-Werte als Objekt zurückgeben
                          → Kein Zugriff auf Bun APIs
                          → Zugriff auf window.React, $

Lösungsansätze

Option A: window.import überschreiben (EMPFEHLUNG)

import() ist ein "pseudo-keyword" und kann NICHT direkt überschrieben werden. Aber: Webpack/Rollup outputten nie raw import() — sie transpilieren zu UMD oder IIFE. Nur ES Module-native Seiten (selten) nutzen es.

Wir können das Syntax-Keyword import nicht intercepten. Alternative: Den Module-Loader von Bun patchen.

Option B: Bun's native Module-Hooks nutzen (Bun API)

// Bun bietet Module-Hooks (bun --preload)
// Wir registrieren einen Loader, der Module-Code durch unseren Realm leitet

Vorteil: Bun-nativ, funktioniert für alle import()-Aufrufe
Nachteil: Nur mit Bun-Know-how, kein Standard

Option C: Transparent Proxy via new Function() Override

Wenn der Module-Code via import() geladen wird und dann new Function() oder eval benutzt, fängt Sprint 14 das bereits ab. Für reine Module ohne dynamic eval: nicht ausreichend.

Entscheidung

Option B — Bun-spezifischer Module Plugin. Bun bietet Bun.plugin() und Module-Hooks die wir nutzen können. Allerdings:

  1. import() in Bun läuft via JavaScriptCore's internal module loader
  2. Module-Variablen (import, export) sind Lexical Declarations — können nicht via with() shadowed werden
  3. Ein Plugin müsste den Module Source-Code durch unseren Realm leiten

Einfachere Alternative: Akzeptieren dass import() nicht voll sandboxed werden kann und als Known Limitation dokumentieren — wie (0,eval).

Akzeptanzkriterien

  • Option A/B/C bewertet
  • Falls implementierbar: import() läuft im with(_win)-Scope
  • Module sehen Browser-APIs (window, document, React)
  • Module sehen KEINE Bun/Node-APIs
  • export wird korrekt nach aussen gereicht

Betroffene Dateien

Datei Änderung
src/js/execution-realm.ts executeModule() — Module via Realm statt nativem import()
tests/unit/sprint15-import-sandbox.test.ts 10+ Tests

Dependencies

  • Sprint 14 (new Function Sandbox — Basis für Sandbox-Strategie)
  • #70 (indirect eval — gleiche Kategorie "unfixable per Spec")

Technische Risiken

  • import() ist ein Syntax-Keyword — kann nicht wie Function überschrieben werden
  • Module haben Lexical Declarationsimport/export sind nicht shadowable via with()
  • Bun's Plugin API könnte sich ändern
  • ES Module CDN-Lader (esm.sh, unpkg) könnten zukünftig relevanter werden

Performance-Impact

Minimal — import() wird selten genutzt (Webpack/Rollup outputten UMD/IIFE).

## Dynamic `import()` — Sandboxed Module Execution **Priorität:** Niedrig (~0.5% der Seiten) **Abhängigkeit:** Sprint 14 (new Function Sandbox) ✅ ### Problembeschreibung `import('https://cdn.example.com/module.js')` läuft aktuell via Bun's nativem `import()`, was im **globalen Bun-Scope** ausgeführt wird. Module haben Zugriff auf `Bun`, `process`, `Buffer` etc. — die Sandbox wird umgangen. ```javascript // Aktuell: Module läuft in Bun's globalem Scope import('https://cdn.example.com/mod.js') // → Module sieht Bun, process, Buffer (Sicherheitslücke) // → Module sieht NICHT React, $, etc. (Kompatibilitätsproblem) ``` **Betroffene Seiten:** Seltene Fälle von ES Module CDN-Ladern (z.B. `import('https://esm.sh/react')`) ### Architektur-Analyse **Aktueller Ablauf:** ``` Page Code → import(url) → Bun's native Module Loader → Module läuft in globalem Scope → Zugriff auf Bun APIs (escape) → Kein Zugriff auf window.React, $ (broken) ``` **Gewünschter Ablauf:** ``` Page Code → import(url) → Unser intercepter Module Loader → Code via with(_win)-Realm evaluieren → Module-Werte als Objekt zurückgeben → Kein Zugriff auf Bun APIs → Zugriff auf window.React, $ ``` ### Lösungsansätze #### Option A: window.import überschreiben (EMPFEHLUNG) `import()` ist ein "pseudo-keyword" und kann NICHT direkt überschrieben werden. Aber: **Webpack/Rollup outputten nie raw `import()`** — sie transpilieren zu UMD oder IIFE. Nur ES Module-native Seiten (selten) nutzen es. Wir können das **Syntax-Keyword `import` nicht intercepten**. Alternative: Den Module-Loader von Bun patchen. #### Option B: Bun's native Module-Hooks nutzen (Bun API) ```typescript // Bun bietet Module-Hooks (bun --preload) // Wir registrieren einen Loader, der Module-Code durch unseren Realm leitet ``` **Vorteil:** Bun-nativ, funktioniert für alle import()-Aufrufe **Nachteil:** Nur mit Bun-Know-how, kein Standard #### Option C: Transparent Proxy via new Function() Override Wenn der Module-Code via `import()` geladen wird und dann `new Function()` oder eval benutzt, fängt Sprint 14 das bereits ab. Für reine Module ohne dynamic eval: nicht ausreichend. ### Entscheidung **Option B** — Bun-spezifischer Module Plugin. Bun bietet `Bun.plugin()` und Module-Hooks die wir nutzen können. Allerdings: 1. `import()` in Bun läuft via JavaScriptCore's internal module loader 2. Module-Variablen (`import`, `export`) sind Lexical Declarations — können nicht via `with()` shadowed werden 3. Ein Plugin müsste den Module Source-Code durch unseren Realm leiten **Einfachere Alternative:** Akzeptieren dass `import()` nicht voll sandboxed werden kann und als Known Limitation dokumentieren — wie `(0,eval)`. ### Akzeptanzkriterien - [ ] Option A/B/C bewertet - [ ] Falls implementierbar: `import()` läuft im with(_win)-Scope - [ ] Module sehen Browser-APIs (window, document, React) - [ ] Module sehen KEINE Bun/Node-APIs - [ ] `export` wird korrekt nach aussen gereicht ### Betroffene Dateien | Datei | Änderung | |-------|----------| | `src/js/execution-realm.ts` | `executeModule()` — Module via Realm statt nativem import() | | `tests/unit/sprint15-import-sandbox.test.ts` | 10+ Tests | ### Dependencies - Sprint 14 ✅ (new Function Sandbox — Basis für Sandbox-Strategie) - #70 (indirect eval — gleiche Kategorie "unfixable per Spec") ### Technische Risiken - **import() ist ein Syntax-Keyword** — kann nicht wie Function überschrieben werden - **Module haben Lexical Declarations** — `import`/`export` sind nicht shadowable via with() - **Bun's Plugin API** könnte sich ändern - **ES Module CDN-Lader** (esm.sh, unpkg) könnten zukünftig relevanter werden ### Performance-Impact Minimal — `import()` wird selten genutzt (Webpack/Rollup outputten UMD/IIFE).
Artur closed this issue 2026-06-18 17:03:16 +00:00
Author
Owner

Sprint 15 implementiert — Dynamic import() Sandbox

  • var-Blocker im Module-Scope: Bun, process, Buffer, require sind void 0
  • Module-Exports werden in _win gemerged (Object.assign)
  • _win.import = void 0 in Realm-Initialisierung
  • Known Limitation dokumentiert (import() == Syntax-Keyword, analog zu (0, eval))
  • 17 Unit-Tests
  • Commit: 558297b
✅ **Sprint 15 implementiert** — Dynamic import() Sandbox - `var`-Blocker im Module-Scope: `Bun`, `process`, `Buffer`, `require` sind `void 0` - Module-Exports werden in `_win` gemerged (Object.assign) - `_win.import = void 0` in Realm-Initialisierung - Known Limitation dokumentiert (import() == Syntax-Keyword, analog zu `(0, eval)`) - 17 Unit-Tests ✅ - Commit: `558297b`
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
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
glow-all/true-headless-browser#71
No description provided.