Security overview
For security reviewers and the people who sign off on new tools. Everything below describes the current release and is checked by an automated end-to-end test on every build. Things we have not built yet are listed at the bottom, not hidden. Last updated 28 October 2026.
Short version. Gardience runs on your server, inside your network. It never sends data to us and loads nothing from the internet. Every change is checked against the permissions of the person who asked for it and recorded under their name in a tamper-evident log, with a live copy sent to your SIEM. Secrets go in and never come back out.
Where it runs and what talks to what
- Your server, your network. One Linux host with Docker runs the Salt master (3008 LTS), salt-api, the console, and an HTTPS front end. On the standard plans nothing is hosted by us. On a hosted plan we run that server for you, as described below.
- No phone-home. No telemetry, no usage reporting, no license server. The license file is verified offline with an Ed25519 signature and is tied to one server, by the fingerprint of its Salt master key: the one-line installer binds it once, during install (an air-gapped server is bound in your account instead), and nothing checks in after that unless an admin turns on the optional daily release check (Settings > License, off by default), which sends only the license file and the version number. The one-line installer also reports once whether the install finished (operating system, version, and the step it stopped at, nothing about your machines);
--no-report turns that off. The console pages load no outside fonts, scripts, or images (verified by a browser crawl of every page).
- Public security data comes in, nothing goes out. The server downloads public data: CVE lists from Microsoft, Debian, and Ubuntu, CISA's list of exploited vulnerabilities, EPSS scores, DISA's STIGs, and Salt agent installers. These are downloads only. On a network with no internet, CISA's list, EPSS scores, DISA's STIGs, and your scanner's results can be imported by hand. Integrations you turn on (an AI service, Microsoft 365, Slack, PagerDuty, ServiceNow, your SIEM, or backups to your own storage) talk only to the services you name.
- Least privilege inside the server. The console service runs as an unprivileged user with no Linux capabilities. Playbooks run as a separate unprivileged user per run, with no capabilities, under a small supervisor that holds only the rights it needs to switch users and clean up after each run. Both are on read-only filesystems. The Salt master runs as root, as Salt normally does.
- Agents connect in, not out. Windows and Linux agents open a connection to the master on two ports (4505 and 4506 by default). No inbound ports are opened on your endpoints. Windows is managed without WinRM.
- If a paid license lapses, everything keeps working for 30 days. After that the console becomes read-only, except security work, which never stops: installing updates, the reboots that finish them, re-applying the security baseline, and patch rollouts made of those steps. Your fleet, agents, and data keep running.
- Installs without internet. An offline bundle ships every container image prebuilt, so a disconnected network needs nothing from outside.
Controls
Sign-in
- Single sign-on with SAML 2.0 or OpenID Connect, the standards Microsoft Entra ID, Okta, Google, and Ping all speak. Our automated tests run against Keycloak; we confirm your identity provider with you during onboarding. Your IdP groups map to Gardience roles; people in no mapped group cannot sign in
- SSO responses must be signed, are single-use, and bound to the browser that started the sign-in (tested against tampering and replay)
- Or your directory: Active Directory or LDAP
- Or PAM / local accounts (SHA-512 crypt hashes)
- Sessions are validated by the Salt master and re-checked at least every minute. One sign-in covers every open tab in a browser; when every console tab has been closed for a minute, the next visitor signs in again. Local accounts' sessions last 8 hours by default; directory and single sign-on sessions end after 1 hour, so someone disabled or demoted in your directory or identity provider loses access within the hour (or at once with
gardience user signout). Removing someone with gardience user del, changing their role or resetting their password ends their sessions and stops their API keys at once. Someone removed in your identity provider can no longer sign in, and their API keys pause after 7 days without a sign-in
Permissions
- Everyone, admins included, holds a read-only Salt session. Their changes go through Gardience, which checks their rights for every target machine, applies change windows and locks, and then runs the change under a service identity with their name on the record. Nobody can go around Gardience to Salt directly
- Approvals fit the risk: everyday work such as patching runs at once. A change that cannot be undone (wiping a disk, removing the Salt agent, clearing the audit logs) always needs a second person, admins included, and nobody can approve their own request. Hardening or rebooting many machines at once needs a second person for everyone but admins, and one setting extends that to admins. Approval steps in workflows and API keys that need approval put any change you choose behind a second person
- For emergencies, root on the server can open a time-limited break-glass account that Gardience audits, announces, and closes on time
- Gardience carries out approved changes through its own service identity, which holds Salt rights only for the functions Gardience calls. Arbitrary command execution is off on new installs and enforced by the Salt master itself, so even a compromised web service could not run commands; an admin turns it on with one command. The identity's password is random, stored owner-only on the server, never shown to anyone, and every use is recorded with the person it acted for
- Built-in roles: admin, operator, approver, viewer, Windows help desk. Rights can be limited to node groups and commands
- Limits fail closed: if Gardience cannot tell which node groups a limited person may see, they see no machines, not all of them
- Sessions: 8 hours for local accounts, 1 hour for directory and single sign-on accounts; they end at once when a person is removed or their role changes
Change safety
- Two-person approval: the person who launches a run cannot approve it
- Change windows per node group, for console runs, workflows, schedules, API runs, and held work alike; work outside the window is held or refused, and an admin can override with a recorded reason
- Baseline or reboot on more than one machine at once needs a second person
- System locks refuse changes on locked machines, enforced on the machine
Audit
- Every action is logged with who, what, where, and when
- Each entry is chained to the last with a keyed HMAC-SHA256. The key is kept outside the data volume, so someone who can edit the stored log cannot rewrite it to match, and entries cannot be downgraded to an unkeyed hash. The chain is re-verified every 15 minutes and on demand, and a break raises an alert in the console
- Every entry is forwarded to your SIEM or syslog server (TCP, TLS, or UDP) within seconds. If the SIEM is unreachable, forwarding resumes from the last entry handed to the network when it returns, and an entry in flight during a failure may be sent twice. Syslog has no delivery receipt, so an entry the network accepted but your SIEM dropped is not resent; the full log and its verification stay on the server (use TCP or TLS; UDP cannot detect loss)
- CSV export and an auditor evidence pack with checksums
Secrets vault
- AES-256-GCM encryption at rest
- The console and API never display a stored value. Anyone allowed to run commands on a machine a secret is scoped to can read it there, so scope secrets to the machines that need them
- Released only to the specific machines that were in the chosen groups when the secret was saved, and a playbook can only carry a secret to those machines. Ansible group membership is fixed when a machine joins, and later changes wait for an admin, so a machine cannot add itself to an Ansible group to get a secret. Built-in operating system and ring groups follow what each machine reports, so check the member list Gardience shows before saving a secret scoped to one of them
- Kept out of Salt job history and logs (tested on every build)
Network
- HTTPS only, TLS 1.2 and 1.3, HSTS
- Clickjacking and content-sniffing headers; API responses are never cached
- Content Security Policy with a fresh nonce on every page; everything shown in the console is escaped, including machine names
- Internal endpoints are unreachable from outside, and only the Salt API calls the console needs are allowed through
- Agents must use Salt's newest sign-in protocol, blocking downgrade attacks
Ansible without new doors
- Existing playbooks run over the Salt connection: no SSH keys or WinRM to open
- Each run gets its own short-lived token and a per-node encrypted channel
- Playbooks run in a separate sandbox container with no access to Gardience data, keys, or secrets, so a lookup or local task in a playbook cannot reach them. Each run has its own unprivileged user, so one run cannot read another's secrets, and anything a playbook leaves running is stopped when it ends
- Only people allowed to run commands can run playbooks
API and AI assistants
- API keys are scoped (read, operate, or configure for Terraform), expire, and pause when their owner has not signed in for 30 days
- Configure keys are made by admins only, stop the moment their owner is no longer an admin, and never run anything on the fleet: they manage enrollments, groups, saved states, and event rules, and remove machines
- A key can never do more than its owner is allowed to
- Requests to make changes wait for a second person to approve by default
- The built-in MCP server offers read tools and pre-approved runbooks only, never free-form commands, and every call is logged under the key owner with its arguments
- A key limited to node groups can act on and read only those groups
- The built-in AI assistant (optional, off by default) only proposes: it has no Salt access, its proposals pass the same checks as a person's input, and nothing runs until a person presses Run, under their own permissions and approvals. Each request and each run it drafted is in the audit log
- The assistant uses the AI service you choose, including a model you host yourself; its key is stored encrypted, and it is sent only the request, page context, and the names of your groups, runbooks, and allowed commands, never secrets or audit data
- Saved states are checked and written only by the network-less config keeper. While command execution is off, a state cannot run commands either
Disk encryption keys
- BitLocker recovery keys leave each machine only encrypted for Gardience, so Salt's job history and logs never hold one in clear text, and are sealed in the vault
- The recovery kit is encrypted to a certificate whose private key you keep; Gardience never has it. It opens with standard OpenSSL, without Gardience
- A machine is encrypted only after its key is in the vault and in a kit that was emailed or downloaded, so no machine can be locked with a key that exists only on itself
- Showing a key is for admins only and is written to the audit log
Live questions and proof links
- Live questions are a fixed, read-only menu. Inputs must be plain names, numbers, or full paths, and answers are limited to the machines the person may see. Every question is in the audit log
- A proof link lets HR, facilities, or IT upload a record or sign a policy without an account. It is the one page that works without signing in, so it is narrow on purpose
- Each link's token is 256 bits, travels in the URL fragment and a request header (never in a logged URL), is stored only as a hash and sealed in the vault, and expires after 30 days
- A link can add files to its own records and read nothing else. Uploads are size-limited, rate-limited, encrypted at rest, and audited
Hardening and patching
- Scores every node against STIG and CIS-aligned controls, Windows and Linux
- Fixes are checked against the permissions of the person who clicked, recorded under their name, then the node is rescanned
- Drift from your desired state is detected and can be corrected automatically
Your data
- Self-hosted: fleet data, the audit log, secrets, and backups stay on your server. We have no access unless you give it to us for a support session.
- Hosted plans (by written agreement): we operate a dedicated server that only you use, so we have administrative access to that server and to its backups. Its disk is encrypted, Salt's agent ports accept only your networks, and you can move to your own server at any time with a normal backup and restore. Nightly backups are encrypted on the server to a key that never exists on it, so neither a breach of the server nor of the backup storage exposes them. Our access uses keys that last 60 seconds, issued through our own signed-in AWS account and logged, with no standing password or key. When you leave, we delete the server, its disk, its backups, and the backup key, and send you a dated record of what was deleted.
gardience backup writes an archive with owner-only permissions and a SHA-256 checksum file, optionally encrypted with a passphrase; restore refuses an archive that does not match its checksum. It includes the vault key and the Salt master's keys, so a restore brings every agent back without re-trusting a single machine. Store it offline.
gardience upgrade refuses a release whose signature does not verify, takes a backup first, and rolls back on its own if the new version does not become ready (Salt connected, nothing reporting a problem). --check verifies a bundle without changing anything.
- The vault key lives on the Gardience server with owner-only permissions, and its location can be moved to a separate volume.
Supply chain and updates
- Salt versions are pinned and tested together before release (compatibility matrix). Every open-source component is pinned to a reviewed version and listed in the release's software bill of materials.
- Releases are signed (Ed25519) and checksummed. The release key's SHA-256 fingerprint is
e8fda5a277e83b0a96708185b1344fdd5045a2d96ff835ef47a1828799b58e44 (openssl pkey -pubin -in install/release-public-key.pem -outform DER | sha256sum). Upgrades refuse a release that is not newer than the one installed. Base images are pinned by digest and every Python dependency by exact version.
- Each release publishes a CycloneDX software bill of materials for every image (also inside the offline bundle) and must pass two known-vulnerability scans: every pinned Python dependency, and each container image it builds. A fixable high or critical finding blocks the release.
- Gardience patching never upgrades the Salt agent behind your back.
- Security fixes ship within the time your plan states (one week on Starter), and we tell you when they are available.
Not built yet, said plainly
- An independent penetration test. Every release must pass our own security testing with standard tools: an OWASP ZAP attack scan of every endpoint signed in as an admin, nuclei's 14,000+ vulnerability templates, TLS and port scans, Bandit static analysis, and container image scans, plus our own sign-in tampering, permission, sandbox-escape, forged-event, and audit-forgery tests. A separate adversarial code review in October 2026 found issues our tests had missed; the confirmed ones were fixed and are now tested. The latest results are in the security testing report we send on request. No outside firm has run a formal penetration test yet.
- Active-active clustering. Gardience runs as a primary with an optional warm standby: encrypted backups ship to the standby on a schedule and keys every minute; one command promotes it (refused while the old primary still runs) and agents reconnect to it on their own within about a minute, with no re-approval; a returning old primary fences itself. Failover can also be automatic (optional, since 1.3.0): with a witness, the standby takes over only when the primary's signed heartbeat is stale, the primary does not answer it, and it can read the witness, and a cut-off primary stops serving first, so there are never two primaries. Running two live consoles at once is not supported.
- Hardware security module or cloud KMS for the vault and audit keys.
- SOC 2 report. Gardience runs on your server and we hold none of your data, so most reviews do not need one. If yours does, we will tell you exactly where we stand.
Report a vulnerability
Email george@gardience.com with "Security" in the subject. We acknowledge within two business days and do not take action against good-faith research. Data handling on this website is covered by our privacy page.