# Security

Zaxy handles durable memory, so security defaults matter. The most important rule is to keep secrets out of Eventloom payloads. Eventloom logs are designed to persist, replay, and export. Store redacted summaries, references, and non-sensitive identifiers instead of credentials, API keys, bearer tokens, or private customer data.

Eventloom appends apply a final safety net before an event is sealed. Payload keys such as `password`, `api_key`, `authorization`, `token`, `secret`, and `private_key` are replaced with `[REDACTED]`, and common secret-looking string values are redacted even when the field name is generic. The event records a `security` classification with `sensitivity` and `redacted_paths`, so replay can show where redaction occurred without exposing the original value. Treat this as defense in depth, not as permission to send raw credentials.

Production configuration should use secret files. Supported file variables are `NEO4J_PASSWORD_FILE`, `MCP_ADMIN_TOKEN_FILE`, `MCP_REMOTE_AUTH_TOKEN_FILE`, `MCP_OIDC_CLIENT_SECRET_FILE`, `OPENAI_API_KEY_FILE`, and `PATHLIGHT_ACCESS_TOKEN_FILE`. The settings loader reads these paths from process environment or `.env`. Direct env variables take precedence. Secret files should be mode `600` and stored outside the repository when possible.

Remote MCP/SSE must be authenticated. Configure `MCP_REMOTE_AUTH_TOKEN` or `MCP_REMOTE_AUTH_TOKEN_FILE`; clients must send `Authorization: Bearer <token>`. For public multi-tenant deployments, prefer OIDC by configuring `MCP_OIDC_ISSUER`, `MCP_OIDC_AUDIENCE`, and `MCP_OIDC_JWKS_URL`. OIDC mode validates JWT issuer, audience, signature through JWKS, required scope `MCP_OIDC_REQUIRED_SCOPE`, and the session claim named by `MCP_OIDC_SESSION_CLAIM` before setting the remote session scope. Static bearer mode uses `MCP_REMOTE_SESSION_HEADER`, defaulting to `x-zaxy-session-id`, for session scoping. Remote clients should not be able to replay or query another session by choosing a different payload field.

Remote MCP/SSE requests are rate-limited by resolved session ID before the MCP transport handles the request. `MCP_RATE_LIMIT_ENABLED=true`, `MCP_RATE_LIMIT_REQUESTS=120`, and `MCP_RATE_LIMIT_WINDOW_SECONDS=60` provide a process-local fixed-window guard. A rejected request returns HTTP `429` with a `Retry-After` header. This is a single-process control; place a shared limiter or gateway in front of horizontally scaled deployments.

Audit export can be enabled with `MCP_AUDIT_ENABLED=true`. Zaxy appends compact JSONL records to `MCP_AUDIT_PATH`, defaulting to `.eventloom/remote_audit.jsonl`, for allowed, auth-denied, and rate-limited remote requests. Audit records include route, method, outcome, session ID when known, reason, timestamp, and client host when available. They do not include bearer tokens, JWTs, request payloads, or raw query text.

Production also requires `MCP_ADMIN_TOKEN` or `MCP_ADMIN_TOKEN_FILE`. Replay and invalidation are bulk-read or state-changing operations, so they must fail closed when no admin token is configured. Remote sessions still remain session-scoped after admin authorization.

Graph projections are session-scoped. Zaxy stores `session_id` on projected entities and relationships, includes it in the temporal uniqueness constraint, and applies it to exact, keyword, vector, traversal, replay, and invalidation paths. This prevents one remote client from retrieving another client's memory through the shared projection backend.

The default embedded LadybugDB projection stays local to the Eventloom workspace. An optional Neo4j sidecar should use TLS in production. Development compose binds ports to localhost. Production compose enables Bolt TLS and mounts certificates generated by `scripts/generate-certs.sh` or supplied by your platform. The deployment validator rejects production plaintext Bolt usage without a CA certificate when the Neo4j backend is selected.

Input validation and payload sanitization live in `src/zaxy/security.py`. They bound payload size, query length, traversal depth, result limits, and session ID shape, then classify and redact payloads before durable writes. These limits protect the graph and filesystem from accidental or hostile inputs.

Observability also needs care. Pathlight tracing should avoid raw query text unless `TRACE_RAW_QUERIES=true` is explicitly chosen. Raw prompts and queries may contain sensitive context. Prefer hashes, summaries, and structured metadata for routine production traces.

Before promotion run:

    scripts/validate-deployment.sh --root .
    scripts/release-check.sh --root .

See configuration.md, deployment.md, operations.md, mcp.md, and README.md for the surrounding procedures.