Security

Dakera is built with enterprise-grade security from the ground up. Every request passes through authentication, rate limiting, input validation, and injection detection before reaching the engine. All memory content can be encrypted at rest with AES-256-GCM, and comprehensive audit logging provides full operational visibility.

Security layers

LayerProtectionConfiguration
Encryption at RestAES-256-GCM authenticated encryptionDAKERA_ENCRYPTION_KEY
API AuthenticationHierarchical key scopes with namespace restrictionDAKERA_ROOT_API_KEY
Input Validation7 injection patterns blocked, field limits, depth limitsBuilt-in — always active
Security HeadersCORS, CSP, HSTS, X-Frame-Options, and more3 presets (default, permissive, strict)
Rate LimitingGlobal token bucket + per-namespace sliding-windowRATE_LIMIT_RPS, RATE_LIMIT_BURST
Audit LoggingHTTP request audit + business event auditDAKERA_AUDIT_ENABLED=true

Input validation

Dakera's input validation layer is always active and cannot be disabled. It detects and blocks 7 categories of injection attacks before any data reaches the engine:

#PatternWhat it blocks
1SQL injectionClassic SQL payloads ('; DROP TABLE, UNION SELECT, tautologies)
2NoSQL injectionMongoDB-style operators in unexpected fields ($gt, $ne outside filter context)
3Command injectionShell metacharacters and command chaining (; rm -rf, $(cmd), backticks)
4Path traversalDirectory escape sequences (../../etc/passwd, null bytes, encoded slashes)
5XSSScript tags, event handlers, data URIs, encoded HTML entities
6SSRFInternal network addresses, cloud metadata endpoints (169.254.169.254)
7Header injectionCRLF sequences, HTTP response splitting attempts

Field limits

FieldLimit
Memory contentMax body size (DAKERA_MAX_BODY_SIZE, default 10 MB)
Tags per memory50 tags maximum
Tag length256 characters per tag
Agent ID256 characters
Namespace name128 characters, alphanumeric + hyphens
API key name128 characters
JSON nesting depth32 levels maximum

CORS configuration

Cross-Origin Resource Sharing controls which domains can access Dakera's API from a browser context.

# Allow specific origins (production — recommended)
DAKERA_CORS_ORIGINS=https://app.example.com,https://dashboard.example.com
DAKERA_CORS_CREDENTIALS=true

# Allow all origins (development only)
DAKERA_CORS_ORIGINS=*
DAKERA_CORS_CREDENTIALS=false
Never use CORS_ORIGINS=* with CORS_CREDENTIALS=true — this is a security misconfiguration. In production, always list specific trusted origins.

Content Security Policy

Dakera sends CSP headers to prevent XSS and data injection attacks. Three presets are available:

PresetDirectivesUse case
Defaultdefault-src 'none'; frame-ancestors 'none'API-only deployments (no browser UI)
PermissiveCSP and HSTS disabledDevelopment and testing
StrictRestrictive CSP + HSTS with preloadProduction with compliance requirements
# Custom CSP directives
DAKERA_CSP_ENABLED=true
DAKERA_CSP_DIRECTIVES="default-src 'none'; frame-ancestors 'none'; base-uri 'self'"

Security headers

Dakera automatically sets defense-in-depth HTTP headers on every response:

HeaderValueConfiguration
Strict-Transport-Securitymax-age=31536000; includeSubDomainsDAKERA_HSTS_ENABLED (default: true), DAKERA_HSTS_MAX_AGE
X-Frame-OptionsDENYDAKERA_FRAME_OPTIONS (DENY, SAMEORIGIN, or custom)
X-Content-Type-OptionsnosniffAlways on
X-XSS-Protection1; mode=blockAlways on
Referrer-Policystrict-origin-when-cross-originAlways on
Content-Security-PolicyPer preset (see above)DAKERA_CSP_ENABLED, DAKERA_CSP_DIRECTIVES

TLS & HTTPS

Dakera does not terminate TLS natively — this is intentional. Running a single binary without TLS complexity keeps the attack surface minimal. TLS termination belongs at the reverse proxy layer (Nginx, Caddy, Traefik, or a cloud load balancer).

See Deployment → Reverse proxy & TLS termination for complete Nginx and Caddy configurations. For gRPC, configure mTLS at the proxy level when client certificate authentication is required.

Encryption at rest

# Enable encryption via environment variable
export DAKERA_ENCRYPTION_KEY="your-passphrase-min-8-chars"

# Or use a raw 256-bit key (64 hex chars)
export DAKERA_ENCRYPTION_KEY=$(openssl rand -hex 32)

# Rotate keys (re-encrypts all memories atomically)
curl -X POST http://localhost:3300/admin/encryption/rotate \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"old_key":"current-passphrase","new_key":"new-passphrase"}'

API key authentication

Scope hierarchy

ScopePermissionsUse case
readQuery vectors, recall memories, get namespace infoRead-only clients
writeUpsert/delete vectors, store/forget memories (includes read)Applications writing data
adminNamespace management, policy config (includes write)Administrative tools
super_adminKey management, cluster ops, encryption rotation (includes admin)Operators only

API key lifecycle

The complete workflow from bootstrap to rotation:

# 1. Bootstrap root key (set at server start)
export DAKERA_ROOT_API_KEY=$(openssl rand -hex 32)

# 2. Create a scoped application key
curl -X POST http://localhost:3300/admin/keys \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"query-service","scope":"read","expires_in_days":90}'
# {"key":"dk_abc123...","name":"query-service","scope":"read","expires_at":"2026-08-13T..."}

# 3. Restrict key to a namespace (multi-tenant isolation)
curl -X POST http://localhost:3300/admin/keys \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"tenant-a","scope":"write","namespace":"tenant-a","expires_in_days":90}'

# 4. List all keys
curl http://localhost:3300/admin/keys \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY"

# 5. Monitor key usage
curl http://localhost:3300/admin/keys/dk_abc123/usage \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY"

# 6. Revoke a compromised key
curl -X DELETE http://localhost:3300/admin/keys/dk_abc123 \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY"
Best practice: Use the root key only to create scoped application keys, then store it securely. Rotate every 90 days. Never commit to version control.

Namespace isolation

Namespaces provide hard security boundaries in multi-tenant deployments. A key scoped to namespace tenant-a can only access data within that namespace — it cannot read, write, or even discover other namespaces.

Isolation propertyGuarantee
Data isolationMemories, vectors, entities, and KG nodes are namespace-scoped
Key isolationNamespace-scoped keys cannot access other namespaces
Index isolationEach namespace has independent HNSW/BM25 indexes
Policy isolationDecay, AutoPilot, and retention policies are per-namespace
# Create an isolated namespace for a tenant
curl -X POST http://localhost:3300/admin/namespaces \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"tenant-a","config":{"vector_index":"hnsw","encryption":true}}'

# Create a key scoped to that namespace
curl -X POST http://localhost:3300/admin/keys \
  -H "Authorization: Bearer $DAKERA_ROOT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"tenant-a-app","scope":"write","namespace":"tenant-a"}'

Rate limiting

Dakera enforces rate limits at two levels: a global limit (token bucket) and per-namespace sliding window. When Redis is available, rate limiting is distributed across the cluster.

# Global rate limit
RATE_LIMIT_RPS=100              # requests per second (default)
RATE_LIMIT_BURST=50             # burst capacity

When rate limited, clients receive a 429 Too Many Requests response with Retry-After header indicating when to retry.

# Example rate-limited response
HTTP/1.1 429 Too Many Requests
Retry-After: 1
Content-Type: application/json

{"error":"rate_limited","message":"Too many requests. Retry after 1 second."}

Audit logging

When enabled, Dakera logs every API request with authentication context, timing, and optionally the request/response body. Audit logs provide a complete trail for compliance and debugging.

# Enable full audit logging
DAKERA_AUDIT_ENABLED=true
DAKERA_AUDIT_REQUEST_BODY=true      # log request bodies (careful: increases log volume)
DAKERA_AUDIT_RESPONSE_BODY=false    # log response bodies
DAKERA_AUDIT_MAX_BODY_SIZE=4096     # truncate bodies larger than 4KB
DAKERA_AUDIT_EXCLUDE_PATHS=/health,/metrics  # skip noisy endpoints

Example audit log entry

{
  "timestamp": "2026-05-15T14:30:22.456Z",
  "method": "POST",
  "path": "/v1/memories/store",
  "status": 200,
  "latency_ms": 12,
  "key_name": "query-service",
  "key_scope": "write",
  "namespace": "production",
  "agent_id": "assistant-v2",
  "ip": "10.0.1.42",
  "user_agent": "dakera-py/0.11.46"
}

Container security

PracticeImplementation
Non-root userThe official image runs as UID 1000 (dakera user) — never as root
Read-only filesystemMount /data as the only writable volume. All other paths are read-only
No shellDistroless base image — no shell, no package manager, reduced attack surface
K8s security contextSet runAsNonRoot: true, readOnlyRootFilesystem: true, drop all capabilities
Image signingGHCR images are signed with Sigstore cosign — verify before deploying
# Kubernetes security context
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  readOnlyRootFilesystem: true
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]

Network security

PortServiceExposure
3300REST APIVia reverse proxy only — never expose directly to the internet
50051gRPC APIInternal services only — or via gRPC-aware proxy with mTLS
7946Gossip (SWIM)Cluster nodes only — firewall from external access
# UFW firewall rules for a Dakera node
sudo ufw allow from any to any port 443 proto tcp       # HTTPS via reverse proxy
sudo ufw allow from 10.0.0.0/8 to any port 3300         # REST API from internal network
sudo ufw allow from 10.0.0.0/8 to any port 50051        # gRPC from internal network
sudo ufw allow from 10.0.0.0/8 to any port 7946         # Gossip between cluster nodes
sudo ufw deny 3300                                       # Block external REST access
sudo ufw deny 50051                                      # Block external gRPC access
sudo ufw deny 7946                                       # Block external gossip access

Production security checklist

ItemPriority
Root API key with 256-bit+ entropyRequired
Scoped application keys (least privilege)Required
TLS on all external endpoints (reverse proxy)Required
Server behind reverse proxy (never expose port 3300 publicly)Required
Firewall: only expose 443 externallyRequired
Encryption at rest (DAKERA_ENCRYPTION_KEY)Recommended
CORS restricted to application domainsRecommended
Rate limiting tuned for workloadRecommended
Audit logging enabledRecommended
Key rotation schedule (90 days)Recommended
Namespace-scoped keys for multi-tenant deploymentsRecommended
Container runs as non-root with read-only filesystemRecommended
Image signature verification before deployRecommended