What the gateway records
Each request produces three records, and each one holds a different amount of your data.
The span is the only record that holds message content. The gateway writes it under
gen_ai.input.messages and gen_ai.output.messages, and exports it to the project the virtual key names, using the per-project OTLP token the control plane returns in the key’s bundle. A key whose bundle names no trace project, or returns no token, gets no span export at all.
The spend record is what budgets debit from. It holds the organization, project, virtual key, end-user id, trace id, gateway request id, model, request type, the virtual key’s labels, your X-LangWatch-Metadata echo, token usage, cost, duration and, on a failure, the error type and HTTP status.
What the gateway never logs
The gateway does not write request or response bodies to its logs. The access log records the fields in the table above and no headers. The gateway builds the upstream request itself and injects the real provider credential, so the credential your client sent is not the one the provider sees. On the Gemini passthrough lane it dropsAuthorization, X-Api-Key and X-Goog-Api-Key from what it forwards.
Do not send a virtual key on Xi-Api-Key to a /v1beta path. The gateway accepts that header as a virtual key, and the passthrough lane forwards it to Google, which puts your gateway credential in a provider’s request logs. Use Authorization or X-Goog-Api-Key on /v1beta. Xi-Api-Key is for the ElevenLabs routes, which do not use this lane.
X-LangWatch-End-User-Id, X-Litellm-End-User-Id and X-LangWatch-Metadata are read and then deleted at the edge, so they do not travel either.
Where provider credentials live
Your provider credentials are stored in the control plane’s Postgres database, encrypted with AES-256-GCM under theCREDENTIALS_SECRET key. Each stored value includes its own initialization vector and authentication tag.
The gateway needs the decrypted credential to call the provider, so the control plane sends it inside the key bundle over the signed internal channel. The gateway holds the bundle in a per-pod in-memory cache and writes it to no disk. Restarting the pod discards it.
The cached bundle refreshes on three triggers: the JWT’s 15 minute lifetime, the control plane’s change feed when you edit a key or a provider, and a configuration time-to-live of 60 seconds that catches edits the change feed does not announce.
If the control plane cannot be reached, a cached entry keeps serving past its expiry, extended 5 minutes at a time up to 6 hours. A rejection with 401, 403 or 404 evicts the entry at once, so a revoked or disabled key gets no grace. Set LW_GATEWAY_AUTH_CACHE_HARD_GRACE_SECONDS to a negative value to remove the grace window entirely.
How a virtual key is verified
A virtual key secret readsvk-lw- plus a 26 character Crockford base32 ULID. The full secret is shown once, at creation, and is never stored.
The pepper never leaves the control plane, so a copy of the database alone does not let anyone recover a key or mint a matching hash.
Rotation writes a new secret and keeps the previous hash valid for 24 hours, so a deploy that still carries the old secret keeps working. Revocation is terminal, and the key can never be re-enabled.
Gateway and control plane
Every call between the gateway and the control plane, in both directions, is signed with HMAC-SHA256 overMETHOD\nPATH\nTIMESTAMP\nhex(sha256(body)).
The receiver compares the signature in constant time before it checks the timestamp, so the rejection reason does not leak through timing.
Egress controls
A gateway whoseENVIRONMENT is set to anything other than local refuses to start unless the first two guards below are on. Turn them on for any deployment that reaches the public internet.
Network policy on Kubernetes
The gateway Helm chart ships a deny-by-defaultNetworkPolicy. Turn it on with networkPolicy.enabled: true.
Replace
networkPolicy.egressToProviders with explicit CIDR blocks to pin the gateway to a known provider set.
Reporting a security issue
Emailsecurity@langwatch.ai with reproduction steps. Do not open a GitHub issue for a security report.
Also check: Virtual Keys for creating, rotating and revoking keys, Audit log for the record of every change to a gateway resource, RBAC for who can read and change what, Self-hosting: Configuration for the full environment variable reference.