Skip to content

1.15.1 — 2026-07-06

Version 1.15.1 is a security-and-correctness patch that closes the findings of a full-codebase audit. It contains no breaking changes and no module status transitions — every 1.15.0 and earlier API continues to work unchanged. Upgrading is a drop-in.

TIP

This page groups the fixes by theme. The full, per-issue list lives in the CHANGELOG. For how each affected API is meant to be used, follow the module guides linked from each section.

Headlines

  • XSS hardening across every HTML sink — the mutation-XSS fallback in sanitizeHtml, bq-text on raw-text elements, and bq-bind attribute values are all closed against injection.
  • Runtime evaluators can no longer reach code execution — the client with-scoped evaluator shadows dangerous globals, and the DOM-backed SSR evaluator drops its new Function() fallback in favour of the CSP-safe parser.
  • Trusted Types are now actually enforced — the framework's HTML sinks route through a policy when one is active, via the new trustedHtmlForSink() helper.
  • Secure-by-default server credentials — session and CSRF cookies default to Secure, and file-route JSON loaders inherit the action middleware chain.
  • Reactive robustness — self-triggering effects are bounded instead of overflowing the stack, overlapping fetches abort cleanly, and several composables gain disposal paths.

Security fixes

Sanitization & DOM sinks

  • mutation-XSS fallbacksanitizeHtml's serialize→re-parse stability check returned raw, un-escaped textContent when it detected instability. Since every HTML sink assigns that result to innerHTML, an entity-encoded payload plus a foster-parenting construct could smuggle live markup through the defense. The fallback is now HTML-escaped (#162).
  • Trusted Types wiringsanitizeHtml output was never wrapped for an enforced require-trusted-types-for 'script' CSP, so sink writes would throw under strict CSP. The new trustedHtmlForSink() (in @bquery/bquery/security, re-exported from /full) returns a TrustedHTML object when a policy is active and the sanitized string otherwise; setHtml, Collection.html() and insert paths, bq-html, and bq-html-safe all route through it (#171).
  • DOM clobbering — the reserved-id/name denylist gained the many missing high-value targets (attributes, nodeName, getElementById, defaultView, implementation, DOM-traversal properties, …) and duplicate ids within a sanitized fragment are now stripped. This is defense-in-depth — for fully untrusted content, drop id/name entirely (#179).

Directives & SSR

  • bq-text on raw-text elements — values rendered into textarea / title by the default DOM-free SSR renderer are now escaped, closing a stored-XSS break-out (</textarea><img onerror=…>) (#163).
  • bq-bind attribute values — a shared guard now drops inline on* handlers, rejects dangerous protocols on URL attributes and srcset, and sanitizes srcdoc as an HTML sink. Applied to the client directive and both SSR backends (#164).
  • bq-style injection — the pure renderer validates declaration property names and drops values containing ;, {, }, or <, preventing untrusted style objects from injecting extra declarations/rules (#176).

Expression evaluators

  • Client with-scoped evaluatorevaluate / evaluateRaw no longer resolve inherited members or dangerous globals, closing constructor.constructor('…')() and bare Function('…')() code execution. The proxy shadows a denylist (constructor, __proto__, prototype, Function, eval, globalThis, window, self, …); own context properties and method calls on values are unaffected (#168).
  • DOM-backed SSR evaluator — routed through the CSP-safe Pratt parser shared with the pure renderer, removing the new Function() fallback ('unsafe-eval') and a prototype-lookup gap. Both SSR backends now evaluate identically (#167).

Server & i18n & store

  • Secure cookies — session-id and CSRF secret cookies default to Secure; opt out with cookie: { secure: false } for local HTTP dev (#169).
  • File-route loader authorization — JSON loader endpoints now default their middleware to the action middleware chain, so middlewares: [auth] no longer leaves load() output exposed as unauthenticated JSON. Opt out with dataMiddlewares: [] (#181).
  • i18n prototype guards — placeholder and message-key resolution use own-property checks, so a name colliding with an Object.prototype member is left intact instead of substituting the inherited value (#174).
  • store deepClone — skips prototype-pollution keys, so an own enumerable __proto__ no longer reassigns the clone's prototype (#175).

Correctness fixes

  • store $subscribe — notifications iterate a snapshot, so unsubscribing during notification no longer skips the next subscriber (#165).
  • reactive effect recursion — an effect writing a signal it reads is bounded and warns (cyclic effect update detected) instead of overflowing the stack; effects that legitimately settle still converge silently (#166).
  • view compiler — bails to the runtime evaluator on unterminated string / invalid numeric literals rather than emitting a broken module that fails to import (#170).
  • overlapping fetchesuseFetch / useAsyncData abort the superseded in-flight request when a new execution starts (#172).
  • composable disposaldeferred() returns a handle with dispose(); persistedSignal() ties persistence to the signal's own dispose() via a detached scope; new optional effectScope(detached?) parameter (#173).
  • titleTemplate — inserts the title literally, so $&/$1/$`/$' in a title no longer mangle the rendered <title> (#177).
  • debounce{ leading: true, trailing: true } no longer double-invokes a single call (#178).
  • bq-on — invokes handlers by evaluating the expression rather than scanning for (, so a handler resolved through an inner-paren expression (items.find(fn).handler) fires instead of silently no-op'ing (#180).

New, additive APIs

All three are backwards-compatible additions introduced by the fixes above:

  • trustedHtmlForSink(rawHtml) (@bquery/bquery/security, also on /full) — returns a TrustedHTML under an enforced Trusted Types policy, otherwise the sanitized string.
  • effectScope(detached?) (@bquery/bquery/reactive) — when true, the scope is not auto-collected by an enclosing scope.
  • deferred() handle now exposes dispose() to stop its internal effect and scheduled work.

Migration notes

There are no breaking changes in 1.15.1. Upgrade in place.

Two behavioural defaults tightened; both have explicit opt-outs if you relied on the previous behaviour:

  • Server session and CSRF cookies now set Secure. For local HTTP development, pass cookie: { secure: false }.
  • File-route JSON loaders now inherit middlewares. To keep loader endpoints unauthenticated, pass dataMiddlewares: [] explicitly.

Engines

Publish and local validation target Node.js ≥ 24.0.0 and Bun ≥ 1.3.13. See Supported Runtimes.

Released under the MIT License.