Skip to content

fix: normalize resolved island paths for Windows compatibility - #74

Merged
cpojer merged 1 commit into
mainfrom
04-03-fix_normalize_resolved_island_paths_for_windows_compatibility
Apr 3, 2026
Merged

cpojer merged 1 commit into
mainfrom
04-03-fix_normalize_resolved_island_paths_for_windows_compatibility

Conversation

@shulaoda

@shulaoda shulaoda commented Apr 3, 2026 •

Copy link
Copy Markdown
Member

Fixes Windows CI failures in job/69810862040 (pages:react-vue).

Summary

  • Normalize the return value of resolveSpecifier so island component paths always use forward slashes
  • On Windows, path.resolve() produces backslash paths (e.g. E:\project\pages\_Counter.vue), which flow into islandManifest.componentPath and then into the generated client entry's islands map as dynamic import() specifiers
  • Meanwhile, the SSR-rendered data-island attribute uses normalizePath(relative(...)) (forward slashes) as the key — causing a mismatch when initIslands looks up the loader on the client, silently breaking island hydration and HMR on Windows

Impact without fix

  • Island components fail to hydrate on Windows (data-hydrated never set)
  • Island HMR triggers a full re-mount instead of a hot template swap, resetting all reactive state
  • Affects all framework adapters (Vue, React, Solid, Svelte) since they all consume resolveSpecifier

Test plan

  • pnpm test packages/vue/test/integration/vue-pages-client.test.ts — island HMR test passes on Windows CI
  • Verify no regression on Unix/macOS CI

@shulaoda
shulaoda marked this pull request as ready for review April 3, 2026 05:57
@cpojer
cpojer merged commit 6de48cf into main Apr 3, 2026
6 checks passed
@cpojer
cpojer deleted the 04-03-fix_normalize_resolved_island_paths_for_windows_compatibility branch April 3, 2026 06:06
cpojer pushed a commit that referenced this pull request Sep 11, 2026
…ess (#74)

* fix(security): block internal framework routes from external HTTP access

The dispatch worker forwarded all HTTP requests to user workers without
path filtering. Internal framework routes (/__scheduled, /__queue,
/__void/*) were accessible to external attackers. /__scheduled and
/__queue had no authentication, allowing arbitrary cron/queue handler
execution — confirmed exploitable on live infrastructure (200 OK).

Block all /__-prefixed paths in the dispatch fetch handler before routing
lookup. The queue event handler (worker.fetch via WfP binding) and
native scheduled events are unaffected as they bypass the fetch handler.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): add reserved slug blocklist for project creation

No reserved names list existed. Users could register slugs like cname
(the CNAME target for custom domain DNS), admin, api, www, dash, login,
staging, etc. All were confirmed available on live infrastructure.

Add RESERVED_SLUGS set (33 names) checked during project creation,
covering the CNAME target, platform subdomains, infrastructure names,
and common service slugs.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): add denylist for security-sensitive headers in header rules

User-configured header rules could set any response header including
Set-Cookie. On the shared *.void.app domain (not on the Public Suffix
List), a malicious project could set Domain=.void.app cookies readable
by all other tenant subdomains, enabling cross-tenant session fixation.

Add BLOCKED_HEADERS denylist (set-cookie, strict-transport-security,
public-key-pins) that silently drops security-sensitive headers from
user header rules in the dispatch worker.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): prevent usage-suspended users from bypassing via new projects

Usage-suspended users could create new projects and deploy to them. The
new routing entry had no suspended flag (no existing entry to inherit),
and the UsageCounter DO did not re-suspend newly added slugs. Bypass
was indefinite — new projects served unsuspended traffic forever.

Three fixes:
1. Block deploys for suspended users (403 before FormData parsing)
2. Stamp user suspension on routing entries during deploy
3. Re-suspend all slugs in UsageCounter.handleInit when already suspended

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): scope static asset keys by project to prevent cross-project deletion

Static assets were stored in a shared content-addressed namespace
(assets/{hash}). Retention cleanup only checked the current project
retained deployments before deleting. If two projects shared identical
files (same BLAKE3 hash), one project cleanup could delete the other
projects assets. Free-plan worker projects needed only 2 deploys to
trigger eviction.

Scope asset keys to assets/{projectId}/{hash}. Reading falls back to
the legacy assets/{hash} format for backward compatibility. Deletion
only targets project-scoped keys, leaving legacy shared keys as safe
orphans until manual cleanup.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): strip Set-Cookie from ISR cache to prevent cross-user session replay

The ISR cache miss path and KV serializer did not strip Set-Cookie
headers from worker responses before caching. A worker setting
Set-Cookie (e.g., for auth) would have that cookie cached and replayed
to all subsequent visitors until the TTL expired, enabling session
fixation. The stale revalidation path correctly deleted set-cookie but
the initial miss path and deploy-time prerender path did not.

Fix all three paths:
1. Add set-cookie to SKIP_HEADERS in isr.ts serializeHeaders (KV cache)
2. Delete set-cookie in the cache miss edge-cache path (index.ts)
3. Add set-cookie to skip set in deploy.ts serializePrerenderHeaders

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: bump framework (security fixes)

Includes:
- fix(security): escape deferred data in inline script tags (XSS)
- fix(security): filter internal platform bindings from user env

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(security): restrict dashboard ?token= callback to localhost only

The auth callback accepted raw JWT tokens via ?token= query param on any
hostname, including production. An attacker could mint a valid JWT for
their own account and send a victim to /auth/callback?token=<jwt>,
causing login CSRF / session fixation into the attackers dashboard.

Restrict ?token= to localhost/127.0.0.1 only. Production uses the
?code= exchange flow which is not vulnerable (codes are single-use
and server-side exchanged).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: scope header denylist to set-cookie only, test real RESERVED_SLUGS

- Remove HSTS and PKP from blocked headers — they are per-domain and
  safe on custom domains. Only set-cookie has cross-tenant impact on
  shared *.void.app (not on PSL).
- Add TODO about removing denylist once void.app is on the PSL.
- Export RESERVED_SLUGS and import in test to validate the real set.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants