Sprint 15.3: (0, eval)() Escape dokumentieren + Workaround evaluieren #73

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

Indirect eval (0, eval)() — Known Limitation

Status: Unfixable per JavaScript Specification
Priorität: Niedrig (~0% der Seiten betroffen)

Problembeschreibung

(0, eval)("typeof Bun") läuft per ECMAScript-Spezifikation (Section 18.2.1) im globalen Scope. Unabhängig von with()-Blöcken, Proxies oder Scope-Manipulation:

  1. Der Ausdruck (0, eval) erzeugt eine indirekte Referenz auf eval
  2. Indirect eval EXECUTES im globalen Realm (Bun's globalThis)
  3. Der with(_win)-Block hat KEINE Kontrolle
  4. Function-Proxy aus Sprint 14 greift nicht — eval ist kein Konstruktor
// LÄUFT IMMER IM GLOBALEN SCOPE — nicht fixbar
(0, eval)("typeof Bun")  // → "object" (sieht Bun)

// Fixbar (Sprint 14):
new Function("return typeof Bun")()  // → "undefined"

Warum tritt das in der Praxis nicht auf?

  1. UMD-Bundles nutzen this oder self zur globalen Detektion — nicht indirect eval
  2. Webpack/Rollup outputten IIFE — keine eval()-Aufrufe
  3. Polyfills nutzen ggf. new Function() (Sprint 14 fix) — nicht indirect eval
  4. Selbst wenn: Angreifer die (0, eval) aufrufen können, haben XSS — dann ist Sandboxing akademisch

Mögliche Workarounds (nicht empfohlen)

Workaround A: Proxy auf Window global

// THEORETISCH: Wir könnten das Window-Objekt so patchen, dass
// Bun, process etc. als Properties existieren (void 0)
_win.Bun = void 0;
_win.process = void 0;

Aber: (0, eval) läuft im GLOBALEN Scope — sieht _win garnicht.

Workaround B: Bun's globalThis manipulieren

globalThis.Bun = undefined;
globalThis.process = undefined;

Aber: Dann sehen ALLE Pages diese Änderung — zerstört Isolation zwischen Tabs.

Workaround C: Prozess-Sandboxing

Bun.spawn() mit eigenem --eval Prozess. Jede Page in eigenem Prozess.

Aber: Massiver Architektur-Eingriff, Performance-Verlust.

Entscheidung

Kein Workaround. Als Known Limitation dokumentieren. Der Aufwand für einen Workaround (Options C) steht in keinem Verhältnis zum Nutzen (~0% der Seiten).

Tests

  • tests/unit/sprint11-script-security.test.ts — bestehender Test dokumentiert Escape
  • Kommentar im Test erklärt warum das nicht fixbar ist
## Indirect eval `(0, eval)()` — Known Limitation **Status:** Unfixable per JavaScript Specification **Priorität:** Niedrig (~0% der Seiten betroffen) ### Problembeschreibung `(0, eval)("typeof Bun")` läuft per ECMAScript-Spezifikation (Section 18.2.1) im **globalen Scope**. Unabhängig von `with()`-Blöcken, Proxies oder Scope-Manipulation: 1. Der Ausdruck `(0, eval)` erzeugt eine **indirekte Referenz** auf eval 2. Indirect eval EXECUTES im **globalen Realm** (Bun's globalThis) 3. Der `with(_win)`-Block hat KEINE Kontrolle 4. `Function`-Proxy aus Sprint 14 greift nicht — eval ist kein Konstruktor ```javascript // LÄUFT IMMER IM GLOBALEN SCOPE — nicht fixbar (0, eval)("typeof Bun") // → "object" (sieht Bun) // Fixbar (Sprint 14): new Function("return typeof Bun")() // → "undefined" ``` ### Warum tritt das in der Praxis nicht auf? 1. **UMD-Bundles** nutzen `this` oder `self` zur globalen Detektion — nicht indirect eval 2. **Webpack/Rollup** outputten IIFE — keine eval()-Aufrufe 3. **Polyfills** nutzen ggf. `new Function()` (Sprint 14 fix) — nicht indirect eval 4. **Selbst wenn:** Angreifer die `(0, eval)` aufrufen können, haben XSS — dann ist Sandboxing akademisch ### Mögliche Workarounds (nicht empfohlen) #### Workaround A: Proxy auf Window global ```javascript // THEORETISCH: Wir könnten das Window-Objekt so patchen, dass // Bun, process etc. als Properties existieren (void 0) _win.Bun = void 0; _win.process = void 0; ``` ⇒ **Aber:** `(0, eval)` läuft im **GLOBALEN Scope** — sieht `_win` garnicht. #### Workaround B: Bun's globalThis manipulieren ```javascript globalThis.Bun = undefined; globalThis.process = undefined; ``` ⇒ **Aber:** Dann sehen ALLE Pages diese Änderung — zerstört Isolation zwischen Tabs. #### Workaround C: Prozess-Sandboxing `Bun.spawn()` mit eigenem `--eval` Prozess. Jede Page in eigenem Prozess. ⇒ **Aber:** Massiver Architektur-Eingriff, Performance-Verlust. ### Entscheidung **Kein Workaround.** Als Known Limitation dokumentieren. Der Aufwand für einen Workaround (Options C) steht in keinem Verhältnis zum Nutzen (~0% der Seiten). ### Tests - [ ] `tests/unit/sprint11-script-security.test.ts` — bestehender Test dokumentiert Escape - [ ] Kommentar im Test erklärt warum das nicht fixbar ist
Artur closed this issue 2026-06-18 16:55:07 +00:00
Author
Owner

Bereits gelöst: Test in tests/unit/sprint11-script-security.test.ts:204 dokumentiert den Escape als unfixable per JS Spec. Kein Code-Change nötig.

✅ **Bereits gelöst:** Test in `tests/unit/sprint11-script-security.test.ts:204` dokumentiert den Escape als unfixable per JS Spec. Kein Code-Change nötig.
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#73
No description provided.