You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: PHASE2_PLAN.md
+158Lines changed: 158 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -22,6 +22,156 @@ This is a compatibility layer, not a claim of perfect browser-origin spoofing. N
22
22
- Executing unparsed original target JavaScript as a compatibility fallback in strict mode.
23
23
- Server-side session state or server-side target JavaScript storage.
24
24
25
+
26
+
## Pre-Phase-2 hardening gates
27
+
28
+
Phase 2 must not start by assuming the rewriter will close every current gap. The existing Phase 0/1 boundary must first fail closed when rewriting is absent, late, or broken. The following gates are prerequisites for the Phase 2 implementation sequence.
29
+
30
+
### P0: boundary hardening required before rewriter work
31
+
32
+
1.**Tighten target-response CSP**
33
+
34
+
- Current risk: `web/zp-core.js` emits `connect-src * blob: data: <proxy-ws-origin>` for Service Worker-constructed target responses.
35
+
- Why it matters: Phase 2 rewriting cannot be the only egress boundary. If a script source is missed, CSP must still provide defense-in-depth against direct native connections.
36
+
- Required change:
37
+
- Align `ZP.fixedCSP()` with the stricter server-side `zeroCSP`.
38
+
- Restrict `connect-src` to `'self'` plus the proxy WebSocket origin.
39
+
- Re-evaluate `script-src blob: data:` and document any temporary compatibility exception.
40
+
- Required tests:
41
+
- Static policy test rejecting `connect-src *`.
42
+
- Browser E2E fixture attempting direct external `fetch`, XHR, EventSource, and WebSocket egress.
43
+
44
+
2.**Add Service Worker message capabilities**
45
+
46
+
- Current risk: target scripts execute on the proxy origin and can call `navigator.serviceWorker.controller.postMessage()` directly.
47
+
- Sensitive message types include `ZP_WS_OPEN`, `ZP_COOKIE_SET`, `ZP_HISTORY_UPDATE`, `ZP_BASE_UPDATE`, `ZP_SCROLL_UPDATE`, and `ZP_RESOLVE_ENTRY`.
48
+
- Required change:
49
+
- Generate a per-tab runtime capability token.
50
+
- Pass it to the runtime prelude through `__ZP_BOOT`, then keep it closure-private.
51
+
- Require that token on every runtime-originated `ZP_*` message.
52
+
- Validate `event.source.id` against `clientContext` where possible.
53
+
- Remove `firstTab()` fallback from privileged operations such as `openRuntimeStream`.
54
+
- Required tests:
55
+
- Forged page-level `postMessage` to the Service Worker is rejected.
56
+
- Runtime WebSocket and cookie bridge messages still succeed with the valid token.
57
+
58
+
3.**Close blob/data script execution gaps**
59
+
60
+
- Current risk: `URL.createObjectURL` wrapping is worker-oriented and MIME-dependent; blob/data scripts can also be introduced through DOM script loaders.
61
+
- Required change:
62
+
- Before the rewriter exists, block or neutralize target-created blob/data JavaScript execution paths that cannot be routed through the rewrite pipeline.
63
+
- Include empty or unrecognized Blob MIME types in worker bootstrap handling, or wrap all target-created Blob URLs until Phase 2 can classify them.
64
+
- Revisit `script-src blob: data:` together with the CSP gate above.
65
+
- Required tests:
66
+
-`new Worker(URL.createObjectURL(new Blob(["..."], { type: "" })))` is contained or blocked.
67
+
-`<script src=blob:...>` and data URL script attempts do not execute unrewritten target code in strict mode.
68
+
69
+
4.**Fail closed for dynamic JavaScript compilation until the foreground rewriter exists**
70
+
71
+
- Current risk: dynamic compilation paths are listed in this plan, but Phase 0 runtime does not yet block or rewrite all of them.
72
+
- Required change:
73
+
- In strict/pre-strict hardening mode, block or neutralize:
74
+
-`eval` and indirect eval;
75
+
-`Function`, `AsyncFunction`, `GeneratorFunction`, and `AsyncGeneratorFunction`;
76
+
- constructor-constructor escapes such as `({}).constructor.constructor(...)`;
77
+
- string `setTimeout` and `setInterval`;
78
+
-`document.write` / `document.writeln`;
79
+
-`outerHTML`, `template.innerHTML`, `Range.prototype.createContextualFragment`, and `DOMParser.prototype.parseFromString`;
80
+
- inline event handler mutation APIs including `setAttribute`, `setAttributeNS`, `NamedNodeMap.setNamedItem`, `Attr.value`, and handler IDL setters.
81
+
- Required tests:
82
+
-`Function('return location.href')()` and constructor-constructor variants are rewritten or blocked.
- Add conformance-lite E2E tests for open, message, binary, close, protocol, and error paths.
156
+
157
+
12.**Clarify HTML tokenizer error policy**
158
+
159
+
- Current doc comments imply parser-recoverable markup is emitted, while tokenizer errors currently fail.
160
+
- Required change:
161
+
- Decide and document whether malformed HTML is strict fail-closed or recovery-oriented.
162
+
- Align the behavior with Phase 2 strict rewrite failure policy.
163
+
- Required tests:
164
+
- Malformed but common HTML either recovers predictably or produces a safe `MALFORMED_HTML` error document without partial unsafe execution.
165
+
166
+
13.**Validate share URL schemes in the Go share-url package**
167
+
168
+
- Current risk: callers usually validate `http`/`https`, but `internal/shareurl.New()` itself only encrypts a string.
169
+
- Required change:
170
+
- Enforce `http:` and `https:` inside `shareurl.New()` / `NewWithRand()`.
171
+
- Reject `ws:`, `wss:`, `javascript:`, `data:`, and empty or malformed URLs.
172
+
- Required tests:
173
+
- Go unit tests proving HTTP/HTTPS are accepted and WebSocket/non-HTTP schemes are rejected.
174
+
25
175
## Design constraint: why rewriting is necessary but not sufficient
26
176
27
177
`window.location` cannot be fully virtualized by descriptor patching alone:
@@ -418,6 +568,10 @@ Golden tests for:
418
568
- A test page reading `location.href`, `window.location.href`, `document.URL`, and `document.defaultView.location.href` observes the virtual target URL from rewritten code.
419
569
- A hostile test page using `window['loca' + 'tion']`, `Reflect.get(window, 'location')`, iframe clean realms, and `Function('return location.href')` is rewritten or blocked according to strict mode.
420
570
- No tested path changes the top-level URL to the target origin.
571
+
- Direct external `fetch`, XHR, EventSource, and native WebSocket attempts are blocked or routed through ZeroProxy; none use an unclassified native path.
572
+
- Blob/data worker and script fixtures are contained, rewritten, or blocked.
573
+
-`srcdoc` inline scripts and event handlers cannot execute before iframe containment.
574
+
- Request/upload size limits, 307/308 redirect replay behavior, and relay cancellation semantics are covered by integration tests.
421
575
422
576
### Performance tests
423
577
@@ -427,6 +581,8 @@ Golden tests for:
427
581
428
582
## Implementation sequence
429
583
584
+
Before starting item 1, complete the P0 hardening gates above. P1 gates should be completed before broad-site compatibility evaluation, and P2 gates should be tracked as required coverage for Phase 2 acceptance.
585
+
430
586
1. Add rewriter mode configuration and diagnostics plumbing.
431
587
2. Add Rust SWC rewriter crate and WASM build target.
432
588
3. Load rewriter WASM from the Service Worker and expose `rewriteScript()`.
11. Add browser E2E tests and hostile escape fixtures.
441
597
12. Tighten CSP once compatibility data is available.
598
+
13. Re-run and update the pre-Phase-2 hardening gates; no P0 item may remain open for strict mode.
442
599
443
600
## Acceptance criteria
444
601
@@ -453,3 +610,4 @@ Phase 2 is accepted when:
453
610
-`gosuda.org` click navigation and language dropdown navigation remain on proxy-origin `/p` routes.
454
611
- Hostile tests for `window['loca' + 'tion']`, `Reflect.get`, iframe clean realms, and constructor-constructor dynamic code do not expose a native direct-egress path.
455
612
- All strict-mode rewrite failures produce safe ZeroProxy errors instead of executing original target code.
613
+
- P0 hardening gates are complete: strict CSP, Service Worker message capabilities, blob/data script handling, and fail-closed dynamic compilation paths.
0 commit comments