Skip to content

harden auth-free redirect, ssrf pinning, first-admin and quota races, service.name - #263

Merged
Polliog merged 8 commits into
developfrom
fix/security-hardening-leads
Jun 26, 2026
Merged

harden auth-free redirect, ssrf pinning, first-admin and quota races, service.name#263
Polliog merged 8 commits into
developfrom
fix/security-hardening-leads

Conversation

@Polliog

@Polliog Polliog commented Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Fixes five additional issues surfaced by KIberblick.de during the review that produced #262. They were shared as unverified leads; each was confirmed against the code, fixed, and tested. Independent commits, no database migrations.

1. Open redirect on auth-free login/register

In authMode === 'none' deployments, the login and register pages forwarded the user-supplied redirect query param via goto(redirectUrl) with no validation, while the normal submit path already checked it. A shared isSafeInternalPath/safeRedirect helper now guards both paths on both pages, requiring a single-leading-slash path and rejecting protocol-relative forms including the backslash variant (/\evil.com) some browsers normalize to //.

2. SSRF guard DNS rebinding

safeFetch resolved+validated the host, then let fetch() re-resolve at connect, leaving a resolve-then-connect window (the TCP monitor path pinned, the HTTP path did not). The HTTP(S) path now connects through a per-request undici dispatcher whose lookup is pinned to the validated IP; TLS SNI and certificate validation still use the original hostname. Adds undici as a direct backend dependency.

3. First-admin bootstrap race

createUser decided the automatic first-admin promotion with a non-atomic hasAnyAdmin() check then a separate insert, so concurrent registrations in the zero-admin window could all become admin. The check+insert now runs in a transaction holding a Postgres advisory lock, so at most one wins. Only reachable before the first admin exists (closed entirely when INITIAL_ADMIN_* is set).

4. Capability limit check-then-act race

Resource-creating routes (api keys, custom dashboards, alert rules, sigma import/enable, notification channels) ran COUNT -> assertWithinLimit -> insert without serialization, so parallel requests could each pass the check then all insert, exceeding a finite cap (quota bypass, not a tenant boundary; OSS default has no finite limits). A shared withLimitLock now serializes the count+create per org+capability via an in-process mutex wrapping a transaction-scoped Postgres advisory lock. The in-process mutex bounds DB-lock waiters to one per key per instance, so waiters never hold a connection while queued (an earlier transaction-only version exhausted the pool under concurrency).

5. Defense-in-depth on OTLP service.name

Complementing the service-map output-encoding in #262, ingested service.name (logs, spans, metrics) now runs through a shared sanitizeServiceName that strips control characters (C0/DEL/C1, incl. null bytes) and caps length, while preserving otherwise legitimate characters (escaping still happens at each sink). Keeps a raw payload from resurfacing through a sink added later.

Tests

  • First-admin: users-service.test.ts 41/41 incl. a concurrent-registration race test.
  • Capability race: apikeys-limit.test.ts 5/5 incl. a concurrent-create race test; all capability suites 44/44; route suites for the wrapped modules 146/146.
  • service.name: otlp transformer 189/189.
  • SSRF: ssrf-guard.test.ts 18/18 incl. pinned-lookup tests.
  • Open redirect: redirect.test.ts 9/9; svelte-check at baseline.
  • Backend tsc --noEmit clean.

Reported via KIberblick.de (https://kiberblick.de), coordinated disclosure.

@codecov

codecov Bot commented Jun 26, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 98.51485% with 3 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/backend/src/utils/ssrf-guard.ts 93.10% 2 Missing ⚠️
packages/backend/src/modules/sigma/routes.ts 95.65% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

@Polliog
Polliog merged commit 24c6433 into develop Jun 26, 2026
7 checks passed
@Polliog Polliog mentioned this pull request Jun 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant