# Security (/docs/concepts/security)



## Roles and scopes [#roles-and-scopes]

Each member has one role per workspace. A role maps to the scopes its dashboard session and MCP
grants can use:

| Scope | Owner | Admin | Developer | Billing | Viewer |
| --- | --- | --- | --- | --- | --- |
| `catalog:read` | Yes | Yes | Yes | Yes | Yes |
| `balance:read` | Yes | Yes | Yes | Yes | Yes |
| `logs:read` | Yes | Yes | Yes | Yes | Yes |
| `billing:write` | Yes | Yes |  | Yes |  |
| `keys:write` | Yes | Yes | Yes |  |  |
| `agents:write` | Yes | Yes |  |  |  |
| `credentials:write` | Yes | Yes | Yes |  |  |
| `presets:write` | Yes | Yes | Yes |  |  |
| `pipelines:read` | Yes | Yes | Yes | Yes | Yes |
| `pipelines:write` | Yes | Yes | Yes |  |  |
| `cache:write` | Yes | Yes | Yes |  |  |

API keys carry their own scopes and never more than their creator holds. Every operation checks its
scope, and the workspace always comes from the authenticated key, never from the request.

## API keys [#api-keys]

* Stored only as an HMAC-SHA256 with a versioned server-side pepper, and verified in constant time.
  GridRouter cannot show a key again after it is created.
* Checked in order: checksum, lookup, HMAC, expiry, IP allowlist (against the connecting IP;
  `X-Forwarded-For` is never read). Expiry and IP errors are returned only after the HMAC proves the
  caller holds the key.
* Revocation stops billable calls and key management immediately.
* Owners can issue 10 one-time recovery codes (Settings → **Security**). `POST /v1/recovery`
  redeems one for a new owner key if every owner key is lost.

## Vendor credentials [#vendor-credentials]

Each workspace has its own data-encryption key, wrapped by a versioned key-encryption key that only
the vault service can use. Vendor keys are sealed with AES-256-GCM, bound to the workspace, vendor,
slot and credential id, so a ciphertext moved anywhere else fails to decrypt. The API is
write-only; a key is decrypted in memory only for the vendor call.

## Your data [#your-data]

* Logs never contain `Authorization`, cookies, API keys or vault plaintext. Request and response
  bodies are stored only when your options allow it, and `redact_fields` masks named fields.
* The [private cache](/docs/concepts/private-cache) is sealed per workspace, and destroying its key
  makes every cached value unreadable at once.
* Every tenant table in Postgres has row-level security forced on, keyed to the workspace.
* Membership, role, key and credential changes are written to a per-workspace hash-chained audit log.
* Vendor requests go only to reviewed hosts over HTTPS, with no IP literals and every redirect
  re-validated.

## Dashboard sign-in [#dashboard-sign-in]

Email and password with required verification. Five failed sign-ins for one email within 15
minutes lock it for 15 minutes. Sessions last 7 days, and a password reset signs out every other
session. Session cookies are first-party, `HttpOnly` and `Secure`. Settings → **Security** lists
your sessions and signs them out.

## Reporting a vulnerability [#reporting-a-vulnerability]

Email **[security@gridrouter.io](mailto:security@gridrouter.io)**. We acknowledge within 2 business days and fix or mitigate
critical issues within 7 days. Good-faith research against accounts you own is authorized. If you
leak a key, revoke it at once and rotate with a backup key in place.

