Security model ยท CP23.6

Bound authority at every interface.

Trestle separates administrative control, application identity, service automation, storage and outbound delivery. Security claims are tied to implemented controls and retained abuse tests.

Trust boundaries

ActorCredentialAuthority
AdministratorServer-side cookie session + CSRF tokenDashboard and administrative APIs
Application userShort-lived access token; rotating refresh tokenCollection operations allowed by rules
Service accountScoped bearer secretMachine scopes plus collection rules
Personal tokenScoped bearer secretAdministrator-owned automation
Webhook receiverHMAC signing secretVerify deliveries from one target
AWS LambdaProcess-configured AWS credentialsAsynchronous invocation of validated ARNs

Passwords and sessions

Passwords use Argon2id with per-password salts. Administrator setup closes atomically after the first account. Login is rate limited; browser mutations require the session cookie, matching CSRF token and valid origin. Application refresh tokens rotate once, cannot act as access tokens and lose authority when their server-side session is revoked.

Collection authorization

List, view, create, update and delete are independent operations. Application users and service identities must pass the collection rule; services must also possess the exact read or write scope. Individual denials return the same 404 as an absent record.

{
  "list": "actor.id == record.owner",
  "view": "actor.id == record.owner",
  "create": "actor.id == input.owner",
  "update": "actor.id == record.owner",
  "delete": "false"
}

The rule language is deliberately small. See Rule language for the expressions actually implemented.

CP23.6 abuse evidence

A composed matrix attacked cross-owner list/view/update/delete, forged ownership, refresh/access token confusion, service read/write scope confusion and cookie-versus-bearer mutation handling. It found and repaired an individual row-rule bypass; ten repaired repetitions and race-enabled security packages passed. See Battle tested for the exact boundary.

Queries, files and egress

Filters parse into a bounded typed AST and compile to parameterized SQL. Generated storage keys, staged writes and symlink refusal keep client filenames out of paths. Webhooks require HTTPS, reject private/link-local destinations and redirects, re-resolve DNS, bound responses and sign each delivery. Secrets are copy-once; hashes or encrypted values persist according to lookup requirements.

Deployment and reporting

Trestle binds loopback by default. Only configured proxy CIDRs can supply forwarded scheme and client identity. TLS, firewalling, owner-only configuration/data directories, provider-managed S3 recovery and host patching remain operator responsibilities.

Report vulnerabilities privately

Email security@trestle.cv with the affected version, reproduction and impact after removing secrets and personal data. Only the newest release line receives security fixes.

Fail-closed durable mutations

Security-sensitive mutations never report success when their durable write failed. Session revocation, credential revocation, integration enable/disable, job cancellation and rule updates check their write result and return an error on failure, leaving the prior state intact; disabling an application user is transactional. This guarantee is exercised with failure injection on both SQLite and PostgreSQL.