Security model

Security built into the architecture, not bolted on after.

Every guarantee below is enforced by the code path, not by a policy document. Credential headers are scrubbed on every disk and shipped sink by default. Body PII is scrubbed in the mock library and in everything that ships. Each deployment is self-hosted and single-tenant, with per-tenant Row-Level Security policies on every tenant-scoped table as defense-in-depth. The full list of structural invariants is below.

Defense in depth

Application-layer tenant scoping is the authoritative control for data isolation — it should be — and each deployment is self-hosted and single-tenant, so your data never shares a database with another customer's. Per-tenant Row-Level Security policies on every tenant-scoped table sit underneath as a second layer. Everything else on this page is built the same way: misconfigured replay targets don't probe the metadata service, oversized POSTs don't allocate gigabytes of memory, and wrong-but-close tokens don't leak timing.

Guarantees, by construction

Credential headers scrubbed on every disk and shipped sink

A non-negotiable floor of 16 authentication and session headers — Authorization, Cookie, every X-Api-Key / X-Auth-Token / X-Amz-Security-Token variant — is scrubbed by default on every sink that touches disk or leaves the box: the on-disk replay JSONL, the Postgres-backed library, and every shipped/exported stream. The floor is hard-coded, not configurable down; per-deployment add-ons can only EXPAND it. The one place headers stay verbatim is the in-memory active-session store that replays stateful flows byte-perfect — RAM-only, dropped on restart, never written and never transmitted. MOCK_PERSIST_VERBATIM is the explicit, air-gap-only opt-out that keeps headers on the disk JSONL too.

  • ·16 headers, a hard floor that can only expand — never shrink
  • ·Scrubbed by default on every disk sink and every shipped/exported sink
  • ·In-memory replay store keeps headers verbatim for fidelity — RAM-only, never leaves the box; air-gap opt-out persists them via MOCK_PERSIST_VERBATIM

Body PII scrubbed in the mock library and everything that ships

Request and response bodies pass through a structural scrubber on their way into the Postgres-backed mock library and into anything that ships or exports — training data, team deployments, wide-event telemetry. Token formats, payment cards, government IDs, contact information, and cloud credentials are all caught by pattern; sensitive JSON keys (password, secret, api_key, refresh_token, cvv, mfa_code …) are caught by name and their values fully redacted regardless of content. The agent's own on-disk replay JSONL keeps response bodies verbatim by design — exact-fidelity replay is the value, and that file lives on your volume and never leaves the box.

  • ·19 regex categories: JWTs, Bearer/Basic auth, every well-known API key prefix (Stripe, AWS, OpenAI, Anthropic, GitHub), payment cards (Visa/MC/Amex/Discover/Diners), US SSN, email, phone (US + E.164), Bitcoin/Ethereum addresses, IBAN, IPv4
  • ·22-element sensitive-key allowlist — values redacted by name, never inspected
  • ·Structural regex over known PII shapes, not a model — arbitrary high-entropy tokens are NER/entropy roadmap, not caught today
  • ·Library rows carry a scrubbed_at seal: the sync layer refuses to overwrite a scrubbed row with an unscrubbed one

Single-tenant by deployment; per-tenant RLS policies as defense-in-depth

Gostly is self-hosted and single-tenant per deployment — your captured traffic, mocks, and library live in your own database, never co-mingled with another customer's. Within a deployment, every query is tenant-scoped in application code; that is the authoritative isolation control. On top of it, all tenant-scoped tables carry per-tenant Postgres Row-Level Security policies as a defense-in-depth layer.

  • ·Self-hosted, single-tenant per deployment — your data never shares a database with another customer's
  • ·Application-level tenant scoping on every query is the authoritative isolation control
  • ·Per-tenant Postgres Row-Level Security policies defined on all tenant-scoped tables as defense-in-depth

Webhook replay can't probe internal infrastructure

When an operator replays a captured webhook, the target URL is resolved and every IP it points to is classified before any socket opens. Loopback, link-local (including cloud instance metadata), RFC1918 private space, carrier-grade NAT, and IPv6 link-local are all blocked. Blocked ports — SSH, SMTP, every common database driver — are rejected regardless of host. The threat: an authenticated tenant aiming captured POSTs at 169.254.169.254 or a peer service on the same VPC. The fix: refuse before connecting.

  • ·Resolved IPs classified against private/loopback/link-local/CGNAT before any socket opens
  • ·AWS / GCP / Azure instance-metadata endpoints unreachable from replay
  • ·Database, message-broker, and remote-shell ports blocked even on public targets

Request bodies bounded, secrets compared in constant time

Every inbound request is rejected if its body exceeds the configured ceiling — at the layer, before the handler buffers it into memory. A hostile or buggy 10 GB POST cannot force a 10 GB allocation. Authentication tokens — API keys, capture tokens, session-token hashes — are compared in constant time. A wrong-but-close token does not leak its prefix via timing.

  • ·Body-size limit enforced at the streaming layer, not after allocation
  • ·Constant-time comparison on every API-key, capture-token, and session-token check
  • ·Production startup refuses to bind when the infrastructure key is unset

Authentication: password, SAML 2.0, OIDC

Three identity-provider backends are wired and pluggable. Password authentication uses bcrypt at cost factor 12 with a 72-byte input cap. SAML 2.0 supports IdP-initiated and SP-initiated flows, JIT user provisioning, and group-to-role mapping. OIDC ships with JWKS validation, authorization-code flow, configurable scopes, and the same JIT + group-mapping affordances.

  • ·bcrypt cost factor 12; SHA-256 hashing on API keys; constant-time digest comparison
  • ·SAML auto-provisioning of users on first login (configurable)
  • ·OIDC group claim → role mapping (owner / admin / member / viewer)

Four-role RBAC and an append-only audit trail

A four-rank role model — viewer < member < admin < owner — gates every state-changing endpoint. Authentication events (login, logout, SSO, password-reset, session-revoke) and activity events (mutations on services, mocks, repair proposals, scrub configs) are written to dedicated tables. The owner rank carries a hard invariant: the system refuses to demote the last owner of a tenant.

  • ·viewer / member / admin / owner ranks enforced server-side, not client-side
  • ·auth_audit_events: every login / logout / SSO event with IdP kind, IP, user agent, success flag
  • ·activity_log: every service, repair, scrub, and configuration mutation

License validation with offline grace

The agent verifies its license JWT on a five-minute refresh cycle and caches the validated features for four hours of platform unreachability. A regional outage on Gostly's side does not silently downgrade a customer's stack — they continue with their licensed tier until the grace window closes, at which point degradation is explicit and logged.

  • ·RS256 JWT signed by Gostly platform (KMS-backed key), verified via JWKS
  • ·5-minute fresh TTL · 4-hour stale grace · structured warning when serving stale
  • ·After grace: explicit degradation to free-tier features, never silent

What leaves your infrastructure

The captured traffic on your proxy stays on your proxy. Request bodies, response bodies, full URLs, authentication headers, cookies, API keys, session tokens, raw service identifiers, and customer IP addresses are never transmitted to Gostly servers and never read by any process outside your stack.

The agent does report opt-out-able usage telemetry — counts of recorded mocks, served mocks, generation success/failure, feature gate hits — for product analytics. Identifiers in that stream are salted SHA-256 hashes; raw identifiers and bodies never appear. The full schema is published at /telemetry along with the single environment variable that disables it.

On the platform side: account data, license validation requests, and Stripe billing events are the only cloud-resident state. The traffic library that powers your mocks is yours — on disk, on your Postgres, on your infrastructure.

Compliance posture

Gostly is engineered against the controls regulated buyers ask for: structural redaction, tenant isolation, role-based access, audit trail, SSO. We have not engaged a third-party auditor for SOC 2 Type II or ISO 42001 yet; we share security artifacts (architecture diagrams, the sub-processor list, deletion procedure) under NDA on request. Talk to us at sales@gostly.ai if you need a Trust Pack to walk into procurement with.

Want to see how the pieces fit together?

Read the architecture overview