All chapters

Security

This page says what protects a Huntress installation, what does not, and what you should do about it. It is written to be checked against.

Accounts and sign-in#

  • Passwords need at least 12 characters. Five failed attempts lock the account for five minutes, and a locked account stays locked for passkeys too.
  • Two-factor sign-in with an authenticator app (time-based codes) and eight one-time recovery codes. Set it up under My account → Security.
  • Passkeys (WebAuthn / FIDO2) let a person sign in without a password. Register, name and delete them under My account → Security.
  • Sessions. The cookie is HTTP-only, SameSite Lax, always Secure in production and slides over 8 hours.
  • Registration is closed unless an invitation key is set, compared in constant time and rate limited.
  • Bot trap. The sign-in and registration forms ask no question. An invisible check (a decoy field, a script-answered challenge and a signed, expiring token) runs before the password or key is looked at, so a robot cannot test credentials or lock an account out.
  • Password reset is an e-mailed link and needs mail and AppBaseUrl. Without them it logs an error and sends nothing.
  • Sign-in history (time, address and browser of each sign-in) is on My account. Deleting your own account needs a code sent by e-mail.

Roles and isolation#

See Concepts for what each role can do. Roles are read from the database on every check, so a change applies at once, and every action re-checks it on the server, not only in the page.

  • Owners and Admins add members by name, e-mail and role. There is no invitation e-mail: Huntress generates a password that the administrator hands over, and the member should change it. A member shows as Verified once they have signed in.
  • Organisations are isolated. Every query filters on the organisation, ids sent by a page are checked against it, and tokens and keys carry it. The ingest paths enforce it too: a token maps to one organisation, and rate limits are per organisation.
  • Sensitive device outputs (locks, door strikes, gates, valves, sirens) need an Owner or Admin.

Secrets#

Secrets and where they live
SecretUsed forStoredNotes
Sensor, person and panel tokensA device reportingIn the databaseIn the URL, so they appear in a device's configuration. Replace the sensor on suspicion. Shortened to eight characters in logs.
API keys (hnt_…)The provisioning APIOnly a SHA-256 hashShown once. Revocable. Suspended when their creator stops being an Owner or Admin.
Edge secretsAn edge connectingA hashCompared in constant time; one edge per camera.
Alarm-panel AES keysEncrypted DC-09In the database, unencryptedShown only on the panel's settings page; never logged.
RTSP URLs with credentialsReading a cameraIn the database, unencryptedSent to the edge that serves the camera. Use view-only camera accounts.
HTTP output header valuesCalling a deviceIn the database, unencryptedShown only on the output's settings page; never logged.
The Zigbee network keyThe Zigbee networkA file in zigbee/Protected by file permissions only.
Cookie and bot-trap signing keysSessionsFiles in keys/Protected by file permissions only.
No encryption at restHuntress does not encrypt its database or files itself. Treat the machine as the vault: use full-disk encryption, restrict the data and configuration folders to the service account, and protect backups as you would the server.

Network exposure#

Listeners
ListenerTLSNotes
Web, Hunt API, edge linksYes, through your proxyUse HTTPS only. HSTS (one year, including sub-domains) is sent in production.
MQTT 1883NoToken as user name, password unchecked.
SMTP 25NoNo authentication and no STARTTLS.
SIA DC-09 2000NoOptional AES encryption of the payload, and a clock window as replay protection.
Contact ID 2001NoNo encryption.

Treat the four plain listeners as private: firewall them to the networks and addresses that need them, or put them behind a VPN, and turn off those you do not use. Unknown account codes and tokens are answered like known ones where that matters, and rate limits apply to the web door.

Web hardening#

  • Security headers on every response: X-Content-Type-Options: nosniff, X-Frame-Options: SAMEORIGIN, Referrer-Policy: strict-origin-when-cross-origin, a restrictive Permissions-Policy and a Content-Security-Policy with default-src 'self'. Because the interface is a Blazor application, the policy has to allow inline scripts and styles; it does not allow other origins for scripts or styles, and the only external origin it allows is the map tile server.
  • Rate limits: 300 requests per second per organisation for the Hunt API, 10 per second per address for unknown tokens, and limits on registration, sign-in and passkey endpoints and on the provisioning API.
  • Rule webhooks and device calls go through an outbound policy that refuses private, loopback and link-local addresses unless you allow them, pins resolved addresses, follows no redirects and caps time and size.
  • Health endpoints show only a status word to anonymous callers.

What connects out#

Huntress has no telemetry or analytics and loads no scripts, styles or fonts from anywhere else. The complete list of outbound connections:

Outbound connections
FromToWhenTurn off
The updaterThe release channel on GitHub, over HTTPSOn the update check, if the updater is installedUpdates:Mode=Off, a local ManifestUrl, or an offline bundle
The serverYour SMTP serverWhen Notifications:Smtp is setLeave the host empty
The serverWebhook and arm/disarm URLs you configureWhen a rule runs themDo not configure them
The serverThe device addresses of HTTP outputsWhen a command or status poll runsDo not configure them
The viewer's browsertile.openstreetmap.orgOn a page with a mapNot drawing maps; this reveals the viewer's address and the area viewed to OpenStreetMap
The recipient's mail clientGoogle FontsWhen opening Huntress's HTML e-mails, if remote content is allowedUse a mail client that blocks remote content

What Huntress records#

Huntress keeps several records of what happened. It does not claim a tamper-evident audit log: these are ordinary database tables, deleted by retention and not signed or chained.

Records
RecordHoldsKept
Raw requestsEvery inbound payload with its protocol and source address, for HTTP, MQTT, SMTP, SIA and Contact ID. Cookies and authorisation headers are never stored.Retention:EventDays; can be switched off with RawRequests:Enabled=false
EventsThe normalised event of every reading, report and detection.Retention:EventDays
Device commandsWho or which rule sent which command to which output, with arguments and the result of every step.Retention:EventDays
Rule firingsWhen each rule fired, for what, and whether it notified.Retention:EventDays
IncidentsTimeline, notes, and who or what resolved it.Retention:ResolvedIncidentDays
Sign-in historyTime, address and browser of each sign-in.Per account; not pruned by retention
LogsWhat the program did.14 days
Not recordedThere is no change log of configuration: edits to rules, sensors, members, roles and API keys are not recorded as such, and there is no audit export. If you need that, ship the logs and database backups to a system that does.

Personal data#

  • Positions, device descriptions and payloads are stored verbatim in events and in raw requests. Switch raw requests off, or shorten retention, if you do not need them.
  • Object detection classifies objects only: no faces, no biometrics, no age, gender or emotion. The result is deleted with its picture.
  • Deleting a sensor, place or person removes its pictures and links; incidents keep their denormalised names.
  • Nothing leaves your server unless you configure it to (see above).

A hardening checklist#

  1. Serve the web door over HTTPS only and set AppBaseUrl and AllowedHosts.
  2. Firewall MQTT, SMTP, SIA and Contact ID to the networks that need them, or turn them off.
  3. Enable full-disk encryption and restrict the data and configuration folders to the service account.
  4. Set a long random Registration:InvitationKey, or leave it empty to keep registration closed.
  5. Turn on two-factor sign-in or a passkey for every Owner and Admin.
  6. Use view-only accounts on cameras and least-privilege API keys with an expiry.
  7. Keep clocks synchronised.
  8. Back up the database, keys/, zigbee/ and the configuration, and test a restore.
  9. Set Updates:Mode deliberately, and read the Updates page.
Connection lost
Attempting to reconnect…