v0.9.2
Released
Feature
Metadata Filters, Admin User Creation & Org-Scoped Status URLs
Generic metadata filters across log search and alert rules, admin-driven user provisioning, editable org/project slugs, org-scoped public status page URLs (BREAKING), plus SIEM heatmap crash fix and three fastify/SvelteKit security bumps.
- Generic metadata filter builder with 7 operators, backed by GIN-indexed JSONB queries and shared with alert rules
- Configurable metadata.* columns in the log search table, persisted per project
- Admins can create users from the dashboard (#198) without enabling public signup
- BREAKING: public status page URLs moved to /status/:orgSlug/:projectSlug
- Security: fastify 5.8.5 and SvelteKit 2.57.1 bumps (3 CVEs, 2 HIGH / 1 MEDIUM)
Added
- Generic metadata filters in log search and alert rules: the search page and alert rule dialogs now expose a “Metadata filters” section backed by a new
MetadataFilterBuildercomponent. Supported operators:equals,not_equals,in,not_in,exists,not_exists,contains. Filters are applied server-side via a GIN-indexed JSONB query builder in reservoir; alert evaluation also runs the same matcher in-process so rules can fire only when a specific metadata field matches - Configurable metadata columns in log table view: users can add arbitrary
metadata.*keys as extra columns in the search results table via a “Columns” picker. The selected column set is persisted per project in localStorage so it survives page reloads - Create user from admin panel (#198): admins can now provision new accounts directly from
Admin → User Managementvia a “Create User” button, without having to temporarily re-enable public signup. Opens a dialog to set email, name, password and optional admin role. Backed by a newPOST /api/v1/admin/usersendpoint that bypasses theauth.signup_enabledgate and logs acreate_userentry to the audit log - Set a custom dashboard as default from the UI: the dashboard switcher now shows a clickable star next to each org-wide, non-personal dashboard; clicking it promotes that dashboard to be the org’s default. Backed by a new
POST /api/v1/custom-dashboards/:id/set-defaultendpoint that atomically unsets the previous default and sets the new one in a single transaction, respecting the existing partial unique index. Personal and project-scoped dashboards are rejected with a 400 - Editable project slug from monitoring page: the status-page settings card in
/dashboard/monitoringnow exposes a “Public URL slug” input that lets the user rename a project’s slug, with inline validation against a shared format check (lowercase alphanumeric + hyphens, 2-50 chars), reserved-word list (api,admin,dashboard,status,auth,login,signup,logout,_app,health), and per-org uniqueness. Conflicts surface as 409 with a friendly inline error; race conditions are caught at the DB layer via the new composite unique index - Editable organization slug from settings:
/dashboard/settings/generalslug field is no longer read-only; owners can rename the org slug with the same validation rules and global uniqueness, with a warning that any existing status-page links and embed badges will break
Changed
- Public status page URL is now scoped under the organization (BREAKING): page and badge URLs changed from
/status/:projectSlugto/status/:orgSlug/:projectSlug. Affects the public web page,/api/v1/status/:orgSlug/:projectSlug/badge.svg, and/api/v1/status/:orgSlug/:projectSlug/badge.json. No redirect from the old URLs. Anyone embedding the badge SVG/JSON or sharing a status-page link must update the URL to include the org slug. Migration040simultaneously moves project-slug uniqueness from global back to per-org, so two different organizations can now both have a project namedfrontendwithout auto-suffixing
Fixed
- Security dashboard crashed with “Cannot read properties of null (reading ‘toLowerCase’)” (#200): root cause was two parallel
unnest(mitre_techniques)/unnest(mitre_tactics)calls in the same SELECT list ofSiemDashboardService.getMitreHeatmap. PostgreSQL evaluates sibling set-returning functions in lockstep and NULL-pads the shorter array, so any detection event whose tactic and technique arrays had different lengths produced heatmap rows with a null tactic, which then crashedMitreHeatmap.abbreviateTacticon the frontend. The heatmap query now unnests techniques only and resolves each one to its canonical tactic via the sharedMITRE_TECHNIQUESmap (with sub-technique to parent fallback), eliminating the malformed pairs at the source. FrontendMitreHeatmapalso filters cells with null tactic/technique andDetectionEventsList.getLogLevelClassdefensively handles a nulllevelas belt-and-suspenders
Security
- Bump
fastifyto 5.8.5 (GHSA-247c-9743-5963, CVE-2026-33806, HIGH): body schema validation could be bypassed by prepending a single space to theContent-Typeheader. Parser and validator disagreed on how to trim the header, so the body was still parsed but the schema lookup returned no validator and validation was skipped entirely. Upgraded from^5.8.3to^5.8.5 - Bump
@sveltejs/kitto 2.57.1 (GHSA-2crg-3p73-43xp, CVE-2026-40073, HIGH):BODY_SIZE_LIMITcould be bypassed under certain conditions inadapter-node. Tightened the pnpm override from>=2.53.3to>=2.57.1 - Bump
@sveltejs/kitto 2.57.1 (GHSA-3f6h-2hrp-w5wx, CVE-2026-40074, MEDIUM): callingredirectinside thehandlehook with a location containing characters invalid for an HTTP header threw an unhandledTypeError, enabling DoS if the location included unsanitized user input