Skip to content

Security: achref-soua/helio

SECURITY.md

Security Policy

Supported versions

Helio is pre-1.0. Only the latest release receives security fixes.

Version Supported
latest release
older releases

Reporting a vulnerability

Please report vulnerabilities privately — do not open a public issue.

Include reproduction steps, affected component/endpoint, and impact assessment if you have one.

What to expect

  • Acknowledgement within 72 hours.
  • A fix or mitigation plan within 14 days for confirmed issues (severity-dependent).
  • Coordinated disclosure: we ask for up to 90 days before public details, and credit reporters in the release notes unless you prefer otherwise.

Scope notes

Self-hosted deployments are configured by their operators; misconfiguration of a deployment (e.g. exposing internal services publicly) is out of scope, but hardening guidance contributions are welcome.

v2 security surfaces (what changed and how it is defended)

Surface Defense
Credential vault AES-256-GCM envelopes, row-bound AAD, masked reads only, zero-downtime key rotation (ADR-0019)
Backups Sidecar-owned dumps, checksummed, optional passphrase encryption; downloads stream by DB-row filename only, owner-gated and rate-limited (ADR-0020)
BYO churn models Pickle refused by magic byte; artifacts execute only in a rlimit-sandboxed child process; HTTPS endpoints SSRF-guarded (ADR-0021)
Database Studio Hand-rolled allow-list — auth/credential/secret tables are not browsable by construction; validated writes; full audit; owner-only typed-confirm deletes
First-run setup Locks shut at the first user; rate-limited; instances are invite-only by default afterwards (ALLOW_PUBLIC_SIGNUP=false in the bundle)
REST API keys Per-resource scopes with explicit per-handler checks; org-embedded keys verified by whole-key hash behind RLS
Passwords & sessions zxcvbn gate, enumeration-safe reset, session list/revoke, optional org rotation policy, optional org-required 2FA (any RFC-6238 app)
Install pipeline Release bundles and binaries ship sha256 checksums; helio install verifies before extracting
In-app update Single-purpose socket sidecar runs only the fixed helio update; owner-gated, shared-secret request that carries no command; fully optional (see below)
AI plane The intelligence /v1 API requires a shared INTEL_SERVICE_TOKEN (the bundle generates it); the dashboard is the only caller, so the one tenant-data path outside Postgres RLS can't be driven by anyone else on the network
Server-side fetches Outbound webhooks and credential "test connection" probes are SSRF-guarded — hosts that are, or resolve to, private/loopback/metadata addresses are refused unless explicitly opted in
Connection pooling Optional PgBouncer (transaction mode) is safe by design: the tenant id is set transaction-locally and was verified to never leak across pooled connections (ADR-0022)
Rate limiting & CNI The gateway limiter degrades to an in-memory window if Redis is down (no API outage on a cache blip); the Helm chart ships an opt-in NetworkPolicy restricting the AI plane to web + workers

A full write-up of each hardening pass — findings, fixes, and verification — is in docs/security/: the latest is audit-2.1.0.md (cross-tenant analytics and idempotency fixes plus the live OWASP ZAP baseline), preceded by audit-2.0.9.md.

In-app update sidecar (one-click update)

The optional one-click update (Settings → Updates, the update compose profile) lets an owner update the whole instance from the dashboard. Because recreating the stack needs the Docker daemon, this is the one feature that puts the Docker socket inside a container — effectively host-level access — so its blast radius is contained deliberately:

  • The web app never holds the socket. Only the updater sidecar mounts it. An owner's click writes a small, secret-guarded request to a volume shared with the sidecar; the dashboard cannot run Docker commands.
  • The request carries no command. It is a shared secret plus an optional, validated version tag. The sidecar runs exactly one fixed command, helio update — there is no path from a request to arbitrary execution.
  • Owner-only and audited. The admin:updates permission is owner-only and re-checked on the server; every trigger is written to the audit log.
  • On by default; off is durable. Fresh installs enable it, and helio update self-heals the wiring (so the button appears on existing installs that predate it). To keep it off across updates, install or update with --no-inapp-update, which records the durable sentinel HELIO_INAPP_UPDATE=off and drops update from COMPOSE_PROFILES — removing the sidecar and the socket. A bare HELIO_INAPP_UPDATE=false means "not configured" and is re-enabled by the next helio update; use off (not false) to opt out for good. The terminal helio update works regardless of the setting.

Operators who do not want any container holding the Docker socket should opt out with --no-inapp-update (or set HELIO_INAPP_UPDATE=off and drop the update profile) and update from the terminal. The shared volume is reachable only by Helio's own (trusted, in-network) containers.

There aren't any published security advisories