Husky security guide
Husky is designed to be safe by default for local use, but its HTTP API, dashboard, and subprocess execution model still deserve deliberate hardening in production-like environments.
Security model summary
By default, Husky is optimized for local-first workflows:
- the daemon typically binds the API to localhost only
- the CLI uses a local Unix socket for daemon control
- state is stored in a local SQLite database
- subprocesses run on the same machine as the daemon
If you expose Husky beyond the local machine, treat it like any privileged process-control API.
API exposure
Default posture
If huskyd.yaml leaves api.addr empty, the daemon binds to 127.0.0.1:0 and chooses a free local port. This is the safest default.
If you bind to a stable or non-local address
If you set something like:
api:
addr: 0.0.0.0:8420
also enable:
- authentication
- RBAC when multiple users/roles are involved
- TLS when traffic crosses trust boundaries
Authentication
Husky currently supports:
none— no authbearer— static bearer tokensbasic— HTTP Basic auth with bcrypt password hashes
OIDC is declared in config but not implemented.
Bearer auth
Recommended pattern:
auth:
type: bearer
bearer:
token_file: /etc/husky/tokens.txt
Why token files are preferred:
- easier secret rotation
- avoids committing inline tokens to config
- tokens can be hot-reloaded on SIGHUP /
husky reload
The CLI can also use HUSKY_TOKEN when making authenticated HTTP requests.
Basic auth
auth:
type: basic
basic:
users:
- username: admin
password_hash: "$2a$...bcrypt-hash..."
Important:
- Husky rejects plaintext passwords at load time
- use bcrypt hashes only
- use HTTPS if credentials cross a network
RBAC
RBAC is layered on top of auth.
Built-in defaults when auth is enabled and no explicit rules are defined:
admin— all methods and pathsoperator— all methods and pathsviewer—GET,HEAD,OPTIONSonly
With explicit rbac rules, your rules fully replace the defaults.
Example:
auth:
type: bearer
bearer:
token_file: /etc/husky/tokens.txt
rbac:
- role: viewer
methods: [GET, HEAD, OPTIONS]
paths: ["/api/*", "/ws/*"]
- role: admin
methods: [GET, POST, PUT, PATCH, DELETE, OPTIONS]
paths: ["*"]
TLS
Enable TLS when exposing Husky to other machines or networks.
api:
addr: 0.0.0.0:8420
tls:
enabled: true
cert: /etc/husky/tls/server.crt
key: /etc/husky/tls/server.key
min_version: "1.2"
Optional mutual TLS is supported via client_ca.
Recommendations:
- use TLS 1.2 or 1.3 only
- keep certificates and keys outside the repo
- combine TLS with auth, not instead of auth
CORS and browser access
If you use browser-based access outside same-origin local usage, configure CORS deliberately.
api:
cors:
allowed_origins:
- https://dashboard.example.com
allow_credentials: true
Do not use * unless you fully understand the exposure.
Secret handling
In husky.yaml
Use ${env:VAR} instead of embedding secrets directly.
Examples:
integrations:
slack:
webhook_url: "${env:SLACK_WEBHOOK_URL}"
jobs:
deploy:
env:
API_KEY: "${env:DEPLOY_API_KEY}"
Husky also supports loading a .env file from the same directory as husky.yaml, while keeping explicit process environment variables higher priority.
In huskyd.yaml
Prefer file references for tokens and certificates over inline secret values.
Process isolation and execution
Husky runs shell commands on the local machine. Treat job definitions as code execution.
Recommendations:
- restrict write access to
husky.yamlandhuskyd.yaml - run Husky under a dedicated service account where practical
- keep the data directory owned by the Husky service user
- review scripts invoked by jobs just like application code
- use separate OS users or containers if jobs have very different trust levels
Executor-related controls in huskyd.yaml include:
executor.resource_limits.max_memory_mbexecutor.resource_limits.max_open_filesexecutor.resource_limits.max_pidsexecutor.global_env
These help contain jobs but are not a substitute for full sandboxing.
Network-facing notifications
Notification integrations may send data off-host.
Be deliberate about:
- what message templates include
- whether logs are attached
- whether secrets might appear in command output
- who receives
on_failureoron_sla_breachevents
If logs may contain sensitive data, avoid attach_logs: all.
Data at rest
Husky stores operational data in SQLite:
- run metadata
- reasons and triggered-by fields
- logs
- captured outputs
- alert delivery history
That means your database can contain sensitive operational information. Protect the data directory accordingly.
Recommendations:
- set restrictive file permissions on the data directory
- include the database in host-level backup and encryption policies as appropriate
- use retention settings to reduce long-lived sensitive history
Audit logs
Optional audit log output can write newline-delimited JSON to a dedicated file. If enabled, protect that file with the same care as the database.
Secure deployment checklist
For any shared or remote environment:
- bind to a deliberate address
- enable bearer or basic auth
- add RBAC if you need read-only vs admin users
- enable TLS
- store secrets outside version control
- run under a dedicated user
- restrict access to the data directory
- validate config before reloads
- keep retention bounded if logs may contain sensitive output
Known limitations
- OIDC auth is not yet implemented
- Postgres storage is not yet implemented
- not every future-facing
process,metrics,tracing, orsecretsfield is fully wired operationally yet
Until those surfaces are completed, rely on the implemented local-first controls above.