v0.25.9
Released: 2026-04-26 · Channel: stable · Breaking: no · Security: yes
Summary
Community assets, group assets, and custom emojis now require authentication and a community membership check before they’re served. Closes the workspace-branding leak where anyone with a URL could pull a private workspace’s logo, banner, voice-call background, or custom emojis.
Security
Asset routes are membership-gated
The
/community-assets/{filename},
/group-assets/{filename}, and
/emojis/{id} routes were previously registered as
public — no auth, no caller identity, no membership check. For
private workspaces with confidential branding (customer logos,
internal channel emojis, voice-call backgrounds), the URL leaked via
referrer headers, browser history, accidental shares, or screenshots.
The routes now sit behind the auth middleware, and each handler verifies the requester before serving:
- Community icon / banner — parses
<community_uuid>_<role>.<ext>from the filename and requiresis_community_member. - Custom emoji — looks up
community_idon the emoji record and requiresis_community_member. - Group icon / banner — parses
<group_uuid>_<role>.<ext>, resolves to the parent community, requiresis_community_member. - Voice background — parses
<channel_uuid>_voicebg.<ext>and requireschannel_repo::is_member. - Instance admins / owners always pass.
- Non-members get 404, never 403, so the existence of an asset is not disclosed.
Cache headers flipped from public, max-age=…
to private, max-age=… so shared caches (CDNs,
proxies) cannot serve one user’s response to another.
Added
Service worker fetch interception
Required to make asset auth work transparently in the browser. HTML
<img>, <audio>, and
<style url(…)> can’t set custom
headers on the requests they make — so a service worker
intercepts every gated-asset fetch and re-issues it with an
Authorization: Bearer <token> header attached.
The auth store posts the access token to the service worker on
login, token refresh, and logout via
postMessage. The token lives in service-worker memory
only — never persisted, never reachable from
page-context JavaScript.
Upgrade path
Click Apply in the admin Updates tab. ~30 sec downtime; no schema change. After upgrade the service worker on each connected client will pick up the new asset-interception logic on its next update cycle (or full page refresh).
Client-side cache note
If you have a tab open from before the upgrade, your existing
cached <img> elements will continue rendering.
Reload the tab to pick up the new service worker. New asset URLs
loaded after that point will route through the membership check.
Release artifacts
Container image pushed to
registry.seglamater.app/seglamater/chatalot, cosign-signed
against the published public key.