Security Model
bQuery.js is secure by default. The most common XSS footguns — writing untrusted strings into the DOM — are blocked unless you explicitly opt out. This page summarises the framework's security posture. The full sanitizer API lives in the Security module.
Defaults at a glance
- HTML-writing APIs sanitize. Any API that assigns to
innerHTML-equivalent surfaces (templates, view directives, component HTML, story helpers) routes throughsanitizeHtml(). - Attribute interpolation escapes. Attribute values built from user input are HTML-attribute-escaped, not just HTML-text-escaped.
- Trusted Types ready.
sanitize()returns aTrustedHTMLwhen the runtime supports it, so policies can require trusted content. - No reachable
evalin user surfaces. Use ofnew Function()andevalis restricted to theviewandconcurrencymodules and documented as such (see "CSP exceptions" below). - Cookies and headers validate input.
createServer()'s cookie API rejects header-unsafe characters before they reach aSet-Cookieheader.
API surfaces
import { sanitize, sanitizeHtml, escapeHtml, trusted } from '@bquery/bquery/security';sanitizeHtml(input)— strip dangerous tags, attributes, and protocols from an HTML string.escapeHtml(input)— escape<,>,&,",'for safe text interpolation.sanitize(input)— return a Trusted TypesTrustedHTMLwhen available, otherwise an escaped string.trusted(input)— explicit escape hatch; document why every call is safe.
Trusted Types
bQuery integrates with the Trusted Types browser feature. When a Trusted Types policy is active:
sanitize()returns aTrustedHTMLproduced by the bQuery policy.- Components and view directives accept Trusted Types objects in addition to strings.
- Raw string assignments to
innerHTMLwill throw — as they should.
If your app sets Content-Security-Policy: require-trusted-types-for 'script', bQuery defaults will satisfy it.
CSP and unsafe-eval
Two modules use dynamic function compilation internally:
view— declarativebq-*directives compile to functions for performance. Templates are author-provided, not user input, but the underlying mechanism isnew Function().concurrency— zero-build worker tasks ship source code that the worker compiles at startup.
Both are documented exceptions, not patterns to copy. If your CSP forbids unsafe-eval and you use either module, see the respective module guide for opt-ins (precompiled view templates, pre-bundled worker sources).
Escape hatches
You sometimes need to insert HTML that you already trust (a CMS-rendered fragment, an editor preview):
$('#article').raw.innerHTML = trustedHtmlFromCms; // bypasses sanitizationUse .raw explicitly. Every escape hatch should come with a comment documenting why the input is safe.
Component-level discipline
When authoring components:
- Treat props as untrusted unless the component is internal-only.
- Sanitize before interpolating into HTML templates.
- Use
escapeHtml()for text-style interpolation andsanitizeHtml()for HTML fragments. - Prefer slots over
innerHTMLassembly when projecting child content.
Form serialization
The forms module surfaces user input. The serialization helpers (serializeFormState, readSerializedFormState) treat form IDs strictly — IDs must match [A-Za-z0-9_-]+ and unsupported characters throw rather than being silently normalised.
Server-side guarantees
createServer() (the Server module) layers more defaults:
- Body size limits are enforced by streamed byte count before parsing JSON / form / multipart / text bodies.
- Cookie attribute validation rejects
;,\r, and other header-unsafe characters. ServerHttpErroris the canonical way to surface 4xx / 5xx; status codes propagate throughrenderToResponse.
Reporting vulnerabilities
If you find a vulnerability, follow the Security Policy. Please do not open a public issue for security reports.
See also
- Security module guide
- View module guide — CSP notes
- Concurrency module guide — worker startup model
- Forms module guide — SSR serialization rules
- Server module guide — body limits, cookie validation,
ServerHttpError - Security Policy