Security

Threat model

What Penweir protects, from whom, and what is out of scope.

This is the model we design and test against. It is as much about what Penweir does not cover as about what it does.

What is protected

  1. Sensitive values in requests (identifiers, credentials, customer data), so they do not reach LLM providers the policy does not allow.
  2. Request and response content at rest, which must not exist anywhere.
  3. Provider credentials and the master key.
  4. Control of the gateway’s configuration: who can change what passes.
  5. The audit trail: who used which model and when.

Who it is protected from

Actor Can Penweir’s answer
LLM provider Sees everything a request sends. Redaction and blocking before the call, plus routing restricted to allowed providers. Tests against a fake provider prove the values never left.
Application with a valid key Sends anything. Its pipeline applies, and it cannot choose another one. Unknown fields are rejected, and request size is limited.
Anyone who can reach the gateway port Guesses keys and sends junk. Keys are 43 random characters, stored as digests and compared in constant time. Unauthenticated requests are not processed or audited.
Anyone who can reach the admin port Guesses passwords, CSRF, XSS. argon2id, account lockout, a per-address rate limit, optional TOTP, __Host- HttpOnly SameSite=Strict cookies, CSRF tokens with an origin check, a strict CSP, and no third-party assets. Keep the port internal.
Someone with a copy of the database or a backup Reads it. No payload is stored. Secrets are encrypted with a master key that is not in the database. Keys and session tokens are stored as digests.
Someone with the logs Reads them. Logs are content-free by construction and tested with canaries.
An operator writing a config Points a provider at an internal service (SSRF). Link-local and metadata addresses are refused unless allowed. Credentials in URLs are refused, and redirects are not followed.
The supply chain Ships malicious code. Every dependency is pinned with hashes and justified. Image bases are pinned by digest, CI actions by commit, and npm packages by integrity hash. Vulnerability scans run in CI, and a CycloneDX SBOM ships with every release. The dashboard is static, with no Node in production.

What is out of scope

  • A compromised host or container runtime: it can read process memory.
  • Model behaviour: what a provider does with what it legitimately receives.
  • Detection of unstructured personal data such as names (see what Penweir guarantees).
  • Availability attacks beyond request size limits and timeouts. Rate, token and concurrency limits count in memory for one process, so put a proxy with limits in front if the port is reachable by untrusted clients.

Notable design choices

  • Memory-only request scope. The token vault cannot be pickled, copied or printed, and it is wiped on success, error and cancellation.
  • Failing closed. A pipeline that names an unknown detector, or a provider without its key, makes the gateway not ready rather than running without the step. An invalid licence or master key stops startup.
  • Separate ports. The admin API and dashboard can be firewalled separately from the gateway.
  • Synchronous logging to stdout. If nothing drains stdout, the gateway blocks. Container runtimes always drain it.
  • SSRF check behind a proxy. Without a proxy, the connection goes to the address that was checked. Through proxy_url, the proxy resolves the name again. Use network egress rules as the hard boundary.