Skip to content

[Bug Report] useStack: module-scoped fallback leaks across SSR requests #407

Description

@johnleider

Summary

useStack falls back to a module-scoped singleton (fallbackStack) when no provider/context exists. In SSR (long-lived Node process), overlay tickets registered into this global persist across requests and aren't cleaned up — causing cross-request state bleed (wrong z-index) and unbounded memory growth.

Location

  • packages/0/src/composables/useStack/index.ts:359-365let fallbackStack + lazy getStackFallback().
  • :408-410useStack() returns the fallback when !instanceExists() (and on a useContext miss).
  • :276 cleanup is onScopeDispose, which is unreliable server-side.
  • Documented mitigation already present (:375): "For SSR safety, use createStackPlugin to provide isolated context per app."

Impact

Partial / low. Requires SSR + an overlay component (Dialog / Popover / Snackbar) used without createStackPlugin — which the JSDoc already flags as the wrong SSR setup. Note the "cross-request data leakage" framing (from the source review) is overstated: these are z-index tickets, not user data — it's state bleed + memory growth, not data exfiltration. Aligns with the composable-bar's SSR-hardening priority.

Suggested fix

Guard the fallback under SSR: either throw when no context is provided server-side, or return an ephemeral per-call createStack() (no shared global) on the server, steering consumers to createStackPlugin for coordinated SSR z-index. Add an SSR test.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions