Skip to content

The security model

Plugboard scopes application access by institution and permissions. Production Compose adds database row-level security through its restricted app_user connection. Demo and native deployments use an owner connection, so they do not have that independent database restriction. Connector secrets are encrypted; passwords and API keys are stored as hashes.

Local accounts use a modern memory-hard password hash.

Sessions use short-lived access tokens with revocable refresh tokens. Refresh tokens are revoked in the same transaction that deactivates an account, whether you do it by hand or through SCIM.

Each refresh retires the token it used and issues a replacement. A retired token presented again outside the grace window is treated as a possible replay: the account’s live sessions are ended at first detection. Two requests from the same browser can legitimately race, for example when a page reloads mid-refresh, so a request inside a short grace window is handed the same replacement instead. Before 0.16.0 that replacement could be lost, and staff were occasionally signed out of every device without warning; that no longer happens. A reuse outside the window is recorded in the audit log as Refresh token reuse detected, naming the person and how many sessions were ended. From 0.22.1, presenting that same retired token again does not create another alert or revoke later sessions. The token itself is never recorded.

Two-factor authentication is TOTP, set up by each user under their account. Turning it off requires a current code.

Single sign-on is generic OIDC or SAML 2.0. The OIDC flow uses PKCE and a nonce. See SSO.

Role-based, with fine-grained permissions. A role holding * is a superuser within its own institution, and no permission crosses into another.

The same checks run on the web console, the REST API, the MCP server and the assistant.

Separate permissions allow administrators to distinguish these operations:

  • ticket.internal separates the desk’s own notes from working the queue, so you can give somebody the queue without the notes.
  • charge.raise and charge.approve separate proposing a charge from making it real. Waiving sits with approval.

Tenant-owned records are accessed through the scoped database wrapper. Some deployment-wide identity lookups deliberately resolve the tenant before a scoped query. See tenant isolation for the deployment differences.

Connector credentials are encrypted before they reach the database and decrypted in memory only for the duration of a call. See secrets and keys.

Outbound requests to private, loopback and link-local addresses are blocked by default, so a URL typed into a service monitor or a webhook cannot reach an internal host.

A self-hosted install that monitors LAN addresses opts out:

Terminal window
ALLOW_PRIVATE_EGRESS=1

The setting allows private destinations deployment-wide; it does not permit cloud metadata addresses. Leave it off if the deployment serves more than one institution. A managed deployment uses a connector agent instead, which reaches internal systems without Plugboard requesting a private address.

Guarded requests pin approved addresses and validate redirects. The Ollama connector requires an agent, the operator’s private-egress setting or the exact configured LOCAL_AI_URL origin for private access. See Ollama.

TLS 1.2 is the floor. HSTS is sent, HTTP redirects to HTTPS, and a strict content security policy is applied.

HSTS comes from the application itself rather than from a reverse proxy in front of it, so a deployment that terminates TLS somewhere we did not write the config for still sends it. The default is one year including subdomains, and HSTS_MAX_AGE changes or removes it.

The API honours X-Forwarded-Proto and X-Forwarded-For from a reverse proxy. See HTTPS and certificates.

Applied to authentication endpoints, and to the public API per key.

Audit entries cannot be edited or deleted through the application. Coverage is not complete across all mutations; for example, API-key lifecycle operations currently lack entries. Production app_user also cannot update or delete audit rows; an operator’s database-owner access has broader powers. See the audit log and API-key coverage.

Vendor support operations use a separate deployment credential, with an optional operator identity recorded on audited operations. The product’s support-access switch controls that API; it does not revoke infrastructure administrator access.

Release container images are signed and include an SPDX software inventory. The image scan fails on fixable high or critical vulnerabilities. Source scans and dependency checks provide additional coverage, not a guarantee that no vulnerabilities remain.

Every download has a checksum published beside it, and the automatic updater refuses an archive that does not match. Verification instructions are in updating.

SECRETS_MASTER_KEY, kept somewhere other than the server.

The certificate, and its renewal.

Who holds which role. The product enforces permissions; it cannot tell you that four people should not hold device.manage.

Deciding when to update. Nothing updates itself except the on-premises bundle, and you can turn that off.

Restoring a backup once, to confirm your regime works.

Email [email protected] with reproduction details. The repository security policy targets acknowledgement within two business days and initial assessment within five business days. Avoid posting unpatched vulnerability details publicly.