v0.6.3
BeechCMS v0.6.3
Release Date: July 15, 2026
Pull Request: [#251 — Merge devs into master](#251)
🔒 Security Fixes
- HTML-escape interpolated field values in automation emails — User-authored fields in automation email templates were previously interpolated raw, which could allow malicious users to inject HTML tags (e.g.
<a href="...">or<img src=x onerror=...>script tags) into the email body. They are now properly HTML-escaped before interpolation. (#209) (#244) - Close password-reset timing side-channel — The
/auth/forgot-passwordendpoint previously resolved requests synchronously after sending emails, creating a timing side-channel that allowed attackers to verify whether an email address existed in the database. The email delivery is now handled asynchronously viaexecutionCtx.waitUntil, ensuring consistent response times. (#232) (#245) - Validate public rate-limit seed segment against seed registry — The rate limiter for the public API previously used the request path's first segment directly in the rate-limiter key without validation. This allowed attackers to bypass rate limits or exhaust memory by requesting arbitrary paths (including prototype keys like
constructoror__proto__). The segment is now verified against the seed registry and invalid paths are collapsed into a sharedinvalid-seedbucket. (#203) (#246) - Bind QStash webhook signature verification to endpoint URL — The receiver signature check for the
/qstashwebhook did not bind the verification to the request URL. This left the endpoint vulnerable to cross-endpoint signature replay attacks. The verification now binds to the specific request URL. (#197) (#247) - Reject Object.prototype keys in resolveIcon — The icon registry resolution could be polluted when resolving prototype keys like
constructoror__proto__as icon names, returning native functions or objects instead of React components and causing rendering crashes. It now checks for ownership withObject.hasOwn()before resolving. (#228) (#249) - Close TOCTOU setup race condition — Concurrent POST requests to
/auth/setupcould bypass the "setup already completed" check, allowing multiple admin accounts to be created. This is now prevented by atomically inserting a lock row into the newsetup_completedtable inside the same transaction where the first admin is created. (#233) (#243) - Prevent prototype lookup data loss in queue consumer — The background queue consumer looked up handlers via
jobs[name]. Passing job names matchingObject.prototypeproperties (likeconstructorortoString) could bypass the missing-handler guard and lead to incorrect execution or mis-acked messages. It now usesObject.hasOwn()to restrict lookups to registered job names. (#213) (#240)
🐛 Bug Fixes
- base64url-safe JWT payload decode — Standard
atob()failed to decode base64url-encoded JWT payloads containing URL-safe characters (-,_) or lacking padding, particularly when using UTF-8/unicode characters (like emojis or accents in names), leading to client authentication lockout. A base64url-safe decoder has been introduced. (#227) (#248) - Surface media untrack/decrementStorage failures — If the database update failed (e.g. database locked) after a successful R2 file deletion, the error was silently swallowed. The drift between R2 and the database is now surfaced/thrown so callers can warn about out-of-sync media entries. (#217) (#241)
Upgrading
This release contains critical security fixes for authentication, webhooks, rate limiting, and email rendering. Upgrading is strongly recommended for all deployments. No breaking changes to existing schemas or API contracts are introduced.