1.17.2 — 2026-10-01
Version 1.17.2 is a security patch that closes cookie tossing for the CSRF and session cookies: csrf() and session() now name their cookies __Host-bq.csrf and __Host-bq.sid by default.
It contains no API removals and no module status transitions. Two behaviour changes are listed under Upgrading; the session one logs users out once.
TIP
The full entries are in the CHANGELOG. For how CSRF protection is meant to be used, see Sessions, CSRF, guards, and auth.
Security
__Host- CSRF cookie by default
In signed mode, 1.17.1 keeps the CSRF secret in the server-side session for visitors who have one. Forms rendered without a session, such as the login form, still rely on the CSRF cookie. Anyone who can set cookies for your users (a sibling subdomain, or a network attacker for a cookie set over HTTP) could plant a bq.csrf cookie from a pair minted for themselves.
Browsers accept a cookie whose name starts with __Host- only from the exact host, over HTTPS, with Path=/ and without a Domain. So csrf() now uses __Host-bq.csrf whenever the cookie attributes allow it:
- With the default attributes (
secure: true,path: '/', nodomain) the cookie is__Host-bq.csrf. A plantedbq.csrfis ignored. - With
secure: false(local HTTP dev), a custompathor adomain, the prefix is not allowed and the cookie staysbq.csrf. - An explicit
cookieNamewith a__Host-or__Secure-prefix that the attributes violate throws at startup (see below).
__Host- session cookie by default
The same attack worked on the session cookie. A sibling subdomain could set bq.sid with Domain=example.com, holding a validly signed id for the attacker's own session. The victim's requests then ran in the attacker's account (session swapping, a form of login CSRF): card details or uploads the victim entered landed with the attacker, who also knew the matching session-bound CSRF token.
session() now names its cookie __Host-bq.sid under the same attribute rule, falling back to bq.sid with secure: false, a custom path or a domain. A planted bq.sid is ignored.
Prefix checks at startup
Browsers silently drop a cookie whose __Host- or __Secure- prefix its attributes violate. csrf() and session() now throw at startup for such a cookieName (for example __Host-x with secure: false, or __Secure-x without Secure), instead of every unsafe request failing with 403 or no session ever sticking. A mis-cased prefix such as __host-x throws too: older browsers only enforce the exact spelling, so it would not stop a sibling subdomain from planting the cookie.
The server guide now also spells out the limitation of unsigned mode (no secret): the token is the cookie value, so it does not stop someone who can set cookies for your users. Prefer signed mode with session() wherever the app has sessions.
Upgrading
- CSRF cookie name. With the default attributes the cookie is
__Host-bq.csrfinstead ofbq.csrf.- Server-side verification needs no change.
- A form rendered before the upgrade fails once with
403, as after a secret rotation. - Client code that reads the cookie directly (unsigned double-submit) must use the new name, or pass
cookieName: 'bq.csrf'to keep the old one.
- Session cookie name — users are logged out once. With the default attributes the session cookie is
__Host-bq.sidinstead ofbq.sid.- Sessions issued before the upgrade are not read any more. Accepting the old name as a fallback would reopen session swapping.
- To keep existing sessions for a transition period, pass
cookieName: 'bq.sid'and switch later. Until then the session cookie has no__Host-protection, so a sibling subdomain can still plant one.
- Prefixed cookie names. A
cookieNamewith a__Host-/__Secure-prefix that its attributes violate now throws at startup; such a cookie never worked in browsers. A mis-cased prefix (__host-,__SECURE-) throws as well; spell it exactly.
Engines
Publish and local validation target Node.js ≥ 24.0.0 and Bun ≥ 1.4.0. See Supported Runtimes.