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-texton raw-text elements, andbq-bindattribute 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 itsnew 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 fallback —
sanitizeHtml's serialize→re-parse stability check returned raw, un-escapedtextContentwhen it detected instability. Since every HTML sink assigns that result toinnerHTML, 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 wiring —
sanitizeHtmloutput was never wrapped for an enforcedrequire-trusted-types-for 'script'CSP, so sink writes would throw under strict CSP. The newtrustedHtmlForSink()(in@bquery/bquery/security, re-exported from/full) returns aTrustedHTMLobject when a policy is active and the sanitized string otherwise;setHtml,Collection.html()and insert paths,bq-html, andbq-html-safeall route through it (#171). - DOM clobbering — the reserved-
id/namedenylist gained the many missing high-value targets (attributes,nodeName,getElementById,defaultView,implementation, DOM-traversal properties, …) and duplicateids within a sanitized fragment are now stripped. This is defense-in-depth — for fully untrusted content, dropid/nameentirely (#179).
Directives & SSR
bq-texton raw-text elements — values rendered intotextarea/titleby the default DOM-free SSR renderer are now escaped, closing a stored-XSS break-out (</textarea><img onerror=…>) (#163).bq-bindattribute values — a shared guard now drops inlineon*handlers, rejects dangerous protocols on URL attributes andsrcset, and sanitizessrcdocas an HTML sink. Applied to the client directive and both SSR backends (#164).bq-styleinjection — 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 evaluator —evaluate/evaluateRawno longer resolve inherited members or dangerous globals, closingconstructor.constructor('…')()and bareFunction('…')()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 withcookie: { 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 leavesload()output exposed as unauthenticated JSON. Opt out withdataMiddlewares: [](#181). - i18n prototype guards — placeholder and message-key resolution use own-property checks, so a name colliding with an
Object.prototypemember 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 fetches —
useFetch/useAsyncDataabort the superseded in-flight request when a new execution starts (#172). - composable disposal —
deferred()returns a handle withdispose();persistedSignal()ties persistence to the signal's owndispose()via a detached scope; new optionaleffectScope(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 aTrustedHTMLunder an enforced Trusted Types policy, otherwise the sanitized string.effectScope(detached?)(@bquery/bquery/reactive) — whentrue, the scope is not auto-collected by an enclosing scope.deferred()handle now exposesdispose()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, passcookie: { secure: false }. - File-route JSON loaders now inherit
middlewares. To keep loader endpoints unauthenticated, passdataMiddlewares: []explicitly.
Engines
Publish and local validation target Node.js ≥ 24.0.0 and Bun ≥ 1.3.13. See Supported Runtimes.