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 Neo4j database.

Neo4j 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.

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.