CacheCore
Security Model
CacheCore

Security Model

Cachecore is designed for multi-tenant production deployments. This page covers tenant isolation, authentication, key storage, and data retention.

Tenant isolation

Every cache entry is scoped to a namespace, a SHA-256 hash derived from tenant ID, policy version, system prompt, and tool definitions. Two tenants with different tenant_id values in their JWTs cannot access each other's cache entries. The namespace acts as a cryptographic partition key.

See Namespaces for the full derivation.

JWT authentication

Every gateway request requires a Cachecore JWT:

Authorization: Bearer cc_live_xxxxx.eyJ...

Cachecore verifies the HS256 signature. The JWT payload contains:

ClaimDescription
tenant_idTenant identifier for namespace derivation
project_idProject scoping
policy_versionCache policy version
fresh_ttl_secsPer-tenant fresh TTL override (optional)
stale_window_secsPer-tenant stale window override (optional)
expJWT expiry timestamp

Expired JWTs are rejected. SWR background refresh jobs also check exp: if the originating JWT has expired, the refresh is skipped.

OpenAI key storage

When you upload your OpenAI API key via the dashboard:

  1. Cachecore validates the key with OpenAI
  2. The key is stored in AWS Secrets Manager
  3. The key is never written to an application database, never logged, and never displayed again

The gateway retrieves the key from Secrets Manager at request time using the project ID from your JWT.

Admin API authentication

The /admin/* endpoints require a separate bearer token:

Authorization: Bearer <ADMIN_TOKEN>

The admin token is configured via the ADMIN_TOKEN environment variable on the gateway. It is separate from tenant JWTs. Missing or incorrect tokens return 403 Forbidden.

Rate limiting

Two layers of rate limiting protect the gateway:

ScopeDefaultBehaviour
Per-tenantConfigurable via JWT claimsApplied after JWT validation
Unauthenticated (bypass)100 req/min per IPApplied to requests without Authorization header

Exceeded limits return 429 Too Many Requests.

Data retention

DataStorageRetention
L1 cache entriesRedisfresh_ttl_secs + stale_window_secs (default: 1 hour)
L2 vector entriesRedis HNSWSame TTL as L1; deleted on invalidation
Observation logRedis Stream (cc:obs)Capped at ~10,000 entries, rolling window
OpenAI API keysAWS Secrets ManagerUntil manually deleted

Cachecore does not persist LLM request or response content beyond the Redis TTL. There is no long-term storage of prompts, completions, or conversation history.

What Cachecore does not do

  • Does not share cache entries between tenants
  • Does not log prompt or response content
  • Does not store conversation history beyond cache TTL
  • Does not access your OpenAI key outside of proxied requests