Security

The Cordy Gateway trust model — self-hosting, key hashing, credential encryption, per-key limits, audit logging, and an honest statement on compliance.

This page states plainly what Cordy Gateway protects, how, and what it does not claim. It is a self-hosted, single-tenant product: the security posture is largely determined by how you deploy and operate it.

Trust model

Cordy Gateway runs entirely on your infrastructure:

  • Your keys. Upstream provider credentials live in your database, encrypted at rest. You issue and revoke the wnx_ keys your clients use.
  • Your data store. Prompts pass through the gateway to the upstream provider you configured; they are not sent to Cordy or any third party. Configuration and usage records live in your own PostgreSQL.
  • No third-party dependency in the request path. There is no phone-home for inference. Licensing is verified offline (see below).

Because it is self-hosted, the boundary of trust is your own network, host, database, and secrets management.

No payload capture by default

By default, the gateway does not capture request or response payloads (your prompts and completions). Usage records store metadata only — model, token counts, cost, status, and timing — which is what powers metering and analytics. Content-capturing evaluation features are opt-in and off by default. If you later enable any content-capturing feature, that is your explicit choice and your data stays in your store.

API keys

  • Client keys are wnx_-prefixed and generated with a cryptographically secure random component.
  • The gateway stores only the SHA-256 hash of each key. The full plaintext is shown once at creation and cannot be recovered afterward — copy it then.
  • Keys authenticate via the Authorization: Bearer header or X-API-Key. Keys in the URL query string are not accepted, so they never leak into access logs, proxies, or browser history.
  • Keys have a lifecycle status (active, inactive, revoked, expired). Revocation takes effect on the next request, and the error code distinguishes revoked from inactive from expired so clients react correctly.

Per-key controls

Each key can be constrained independently:

ControlEffect
ScopesLimit the key to specific endpoint families (chat, completions, embeddings, models, balance, admin). Issue least-privilege keys.
Token quotaCap monthly token usage; over-quota requests get 429 quota_exceeded.
Rate limitCap requests per minute per key.
In-flight limitCap concurrent requests per key (GATEWAY_MAX_INFLIGHT_PER_KEY, default 50).
Model permissionsRestrict a key's owner to a subset of public models.
ExpirySet an expiry date after which the key stops working.

Credential encryption at rest

Upstream provider credentials (channel API keys, and the AWS secret for Bedrock) are stored Fernet-encrypted in the database, never in plaintext. They are decrypted only in memory at request-dispatch time.

  • Encryption keys come from CHANNEL_ENCRYPTION_KEYS, which is mandatory in production — the Admin and Gateway both refuse to start without it.
  • The variable accepts a comma-separated list: the first key encrypts new values; the rest allow key rotation without re-encrypting everything at once.
  • Store the key(s) outside version control, in a secrets manager. Clients never see upstream credentials — only their own wnx_ gateway keys.

Audit logging and RBAC

  • The control plane (Admin) keeps an append-only audit log of administrative actions, and enforces role-based access control for operators.
  • The audit worker can optionally ship audit evidence to object storage with server-side retention/immutability controls when you configure it.
  • Client-facing logs record request metadata (not payloads); the gateway deliberately logs request paths without query strings to avoid leaking secrets.

Network and transport

Harden the deployment boundary:

  • Terminate TLS at nginx or an external proxy; keep DJANGO_SECURE_SSL_REDIRECT=True.
  • Restrict CORS. CLIENT_CORS_ORIGINS is empty by default (deny cross-origin browser access). A literal * is refused at boot in production. List explicit origins only if browsers call the gateway directly.
  • Trust proxies explicitly. Set TRUSTED_PROXY_CIDRS so forwarded client IPs are only honoured from your real proxies, preventing audit-IP spoofing.
  • Gate metrics. /metrics/prometheus is denied in production unless a GATEWAY_METRICS_TOKEN or an allowed CIDR is configured.
  • Keep internal services internal. Postgres, PgBouncer, and Redis are not published to the host in the production compose — keep it that way.

Licensing

Cordy Gateway uses an offline, HMAC-signed license. There is no network license check. Enforcement defaults to audit_only (fail-open — it logs but never blocks); strict mode is available if you want it to fail closed. Licensing does not transmit any usage data off the host.

Compliance

Cordy Gateway does not claim any compliance certifications. It is not certified for SOC 2, ISO 27001, HIPAA, FedRAMP, PCI DSS, or any similar standard, and this documentation makes no such claim.

What it does provide are honest, verifiable properties you can build on:

  • Self-hosted and single-tenant — your data stays on your infrastructure.
  • No payload capture by default.
  • Credentials encrypted at rest; API keys stored only as hashes.
  • Per-key scopes, quotas, and rate limits.
  • An append-only administrative audit log with RBAC.

Whether a given deployment meets a specific regulatory requirement depends entirely on how you operate the host, network, database, and secrets — that responsibility is yours.

Hardening checklist

  • CHANNEL_ENCRYPTION_KEYS set identically on Admin and Gateway, stored in a secrets manager.
  • Strong, unique DJANGO_SECRET_KEY and DB_PASSWORD.
  • TLS terminated; DJANGO_SECURE_SSL_REDIRECT=True; a non-obvious DJANGO_ADMIN_URL.
  • CLIENT_CORS_ORIGINS explicit (never * in production).
  • TRUSTED_PROXY_CIDRS set to your real proxies.
  • /metrics/prometheus gated by token and/or CIDR.
  • API keys issued least-privilege (scopes, quotas, expiry).
  • Internal services (Postgres, Redis, PgBouncer) not published to the host.
  • Backups configured and tested; PITR enabled for production.

Next steps

  • Configuration — the security-relevant variables in full.
  • Deployment — applying these controls to a production topology.