A proxy that records API traffic is a proxy that sees credentials, tokens, and potentially sensitive response data. We take that seriously — not as a policy promise, but as an architectural constraint. Here's exactly what we do and why.
The most common question we get from security-conscious teams is straightforward: "Your proxy sees every API call. What happens to my credentials?"
It's the right question to ask. Here's the complete answer.
Gostly uses two separate data stores with different purposes and different safety properties. Understanding the distinction is the foundation of the security model.
Local JSONL (verbatim)
Raw recorded traffic. Lives on your machine only. Headers are redacted at write time. Response bodies are verbatim — this is intentional for test fidelity. Never transmitted externally.
Postgres (scrubbed)
Scrubbed mock library. PII and credentials removed by the transition pipeline. Used for AI training and team deployments. Safe to move off-machine.
The verbatim store and the scrubbed store are never conflated. Each has its own invariants and the architecture enforces them.
The JSONL traffic files written during LEARN mode live in a Docker volume on the machine running the proxy. They are never transmitted to Gostly servers, never included in telemetry, and never read by any process outside your stack.
In a managed Postgres (Team tier) deployment, the Postgres rows may live outside your local machine — but only scrubbed rows, never raw ones. The scrubbing pipeline runs locally before anything is written to Postgres.
Response bodies are written verbatim to the local JSONL files. This is intentional — tests that pattern-match on specific field values only work because the data is accurate. Gostly doesn't infer what the API probably returns; it records what it actually returned in whichever environment you pointed it at (local, staging, or production — your choice).
When you trigger a transition, the scrubbing pipeline applies your configured redaction rules to bodies before writing to Postgres. Configured scrub paths (e.g. $.user.email, $.payment.card_number) are replaced with [REDACTED] and the row is marked with a scrubbed_at timestamp that acts as a permanent safety boundary. A scrubbed row can never be overwritten with raw data.
Credential headers are redacted before any I/O occurs — at the moment the proxy reads the request, before writing to disk. This is the non-overridable floor:
authorization proxy-authorization cookie set-cookie x-api-key x-auth-token x-session-id x-access-token x-user-token x-csrf-token x-amz-security-token x-amz-session-token x-goog-api-key grpc-metadata-authorization api-key token
This list cannot be removed or replaced by configuration. The REDACT_HEADERS environment variable adds to it — it cannot shrink it. The enforcement is structural: it lives in the Rust proxy code, not in a policy document.
Why structural, not policy?
A policy that says "we don't write credentials to disk" is only as strong as the process that enforces it. Structural enforcement means there's no code path that bypasses the redaction — the headers are stripped in the same function that processes every request, before the write even begins.The inference server (the component that generates AI responses for unmatched requests) runs inside your Docker stack. It receives requests from the proxy over the internal Docker network.
No request bodies, response bodies, or API payloads are sent to external model providers. The model (a fine-tuned Qwen variant) runs locally. The retrieval index (for RAG) is built from your scrubbed Postgres rows and stays in your stack.
The only external calls the AI pipeline makes are to the Gostly license server to validate your subscription tier. Those calls contain your license key and a machine identifier — no traffic data.
Beyond the header floor, the redaction list is configurable via the REDACT_HEADERS environment variable (additive only — see above) and via the per-service scrub config in the dashboard at gostly.ai/dashboard/settings/scrub. That page lets you add JSONPath body rules and extra header redactions on top of every default pattern.
Available now — body-level scrub config
PUT /v1/scrub/config upserts your JSONPath body rules; POST /v1/scrub/test previews any rule set against a sample payload before you save. The dashboard surface lives at /settings/scrub.PUT /v1/scrub/config
{
"service_id": "stripe",
"jsonpath_rules": [
{ "path": "$.user.email", "replacement": "<scrubbed>" },
{ "path": "$.source.card.number", "replacement": "<card>" },
{ "path": "$.source.card.cvc", "replacement": "<cvc>" }
],
"header_redactions": ["Authorization", "Cookie", "X-Api-Key", "X-Custom-Auth"],
"enabled": true
}JSONPath expressions are validated at save time — a path that would replace the entire payload (e.g. $ or $..*) is rejected. The goal is targeted redaction, not blanket removal that breaks your test data. The default pattern-based scrub continues to run underneath every per-service config — you can add to the floor, never lower it.
Multi-tenant deployments enforce tenant isolation at the database, not the application layer. Every tenant-scoped table has Postgres ROW LEVEL SECURITY enabled with a policy that scopes every read and every write to the authenticated tenant. The API binds the tenant per-request from the session before any query runs.
Two database roles back this. The role the API connects with has no RLS bypass — a forgotten WHERE tenant_id = …in application code, a SQL injection that escapes parameter binding, or any in-process bug cannot return rows from another tenant. Postgres rejects the query. A separate elevated role exists only for cron jobs and migrations, with its credentials scoped to a connection pool that doesn't see request traffic.
Defense in depth, not single-point-of-failure
Application-levelWHERE tenant_id = … filters still run; RLS is the second wall. The point is that when human code forgets, the database remembers.Self-hosted deployments default to local password auth: bcrypt with a cost factor of 12, password length capped at 72 bytes (the bcrypt limit, not a policy choice), and session cookies marked HttpOnly and Secure.
Team-tier deployments unlock SAML 2.0 and OIDC alongside or in place of password auth. Group-to-role mapping is driven by the IdP's assertion attributes, with a configurable default for users whose groups don't map. Setup specifics — IdP metadata, attribute mapping, role assignment — live in the SSO documentation.
Multi-user workspaces (Team tier) ship four built-in roles:
owner — full control; cannot demote the last owner in a tenant admin — manage users, services, scrub config; cannot delete the workspace member — record traffic, manage their own services viewer — read-only access to dashboards and recorded traffic
Role enforcement runs at every gated endpoint and is mirrored in the dashboard via the <FeatureGate> component, so a viewer who tries to access a member-only page sees the same answer the API would give them. Free and Pro tiers run in single-user mode with the admin auto-bootstrapped on first boot.
Team-tier deployments record every state-changing action — user invitations, role changes, scrub-config edits, service additions — to a tenant-scoped audit log that admins can query through the API. The log itself is RLS-isolated: an admin in tenant A cannot see actions performed in tenant B, no matter which connection pool the request comes through.
To be transparent about what does leave your machine:
Your license key and a machine fingerprint are sent to api.gostly.ai on startup and cached locally for 24 hours. This is how tier features are gated.
When you pull Gostly images from registry.gostly.ai, standard Docker registry logs apply (image name, version, authenticated user).
No traffic data, no API payloads, no response bodies, no scrubbed records are transmitted to Gostly.
Full air-gapped deployment support — local JWKS for license verification, offline image distribution, and a sealed update channel — is on the roadmap for compliance-driven buyers. If you need to evaluate Gostly inside a restricted-egress perimeter today, reach out at security@gostly.ai and we'll work through it with you.
The security model is:
If you have specific questions about data handling for a regulated industry deployment — healthcare, financial services, or anything with specific compliance requirements — reach out at security@gostly.ai. We'll give you a straight answer.