This describes the immediate source changes associated with audit #657. It is not a deployment receipt or a complete installation guide. The full installation contract is tracked in #665; the broader documentation refresh is #667.
Agent execution and GitHub webhook checks apply in development as well as production. Set GITHUB_WEBHOOK_SECRET privately and configure the matching webhook secret before enabling delivery. Selected session, job and workflow endpoints now enforce reader/writer gates before accessing providers or stored results. The remaining route and ownership inventory is tracked in #662.
Opted-in loopback and Tailscale trust admits operational reads only. Writes require an explicit writer credential or an application identity accepted by the route’s permission policy. Community ceremony detail, list and diary access requires a private integration identity, administrator, participant, or circle member/facilitator. A public browser reader token is not a community identity. Network admission still does not implement complete application identity mapping or revocation.
Keep the portal writer and reader values distinct. No reader token is shipped to browsers (jgwill/Miadi#712); pages read through the signed-in person’s cookie. NEXT_PUBLIC_* values are published to browsers. Do not place private credentials there or in URLs. Verified proxy header ownership and direct-port isolation remain requirements for any network trust configuration.
scripts/launch-prod.sh binds 127.0.0.1 unless MIADI_BIND_HOST is explicitly set. Other startup paths and container port mappings must be checked separately. An ngrok tunnel or VPN address alone does not authorize a caller.
Both HTTP MCP entry points require MCP_AUTH_TOKEN with at least 32 characters; provision a randomly generated value privately. This is separate from the portal credential used by MCP tools. Clients must send Authorization: Bearer <token> on /mcp. MCP_HOST defaults to 127.0.0.1; MCP_ALLOWED_ORIGINS contains exact comma-separated browser origins. Requests without an Origin still require the bearer credential. Root/health responses and CORS preflight do not grant tool access. Stdio transport does not need this HTTP ingress token.
Terminal services require a randomly generated TERMINAL_AUTH_TOKEN of at least 32 characters. Tmux may use a separate TMUX_TERMINAL_AUTH_TOKEN; otherwise it falls back to the terminal token. Set exact browser origins in TERMINAL_ALLOWED_ORIGINS. The tmux HTTP response origin also uses TMUX_TERMINAL_ORIGIN when needed.
Existing direct browser terminal connections need an authenticated gateway that validates the person’s authority and supplies the bearer header. Do not place the long-lived operator token in browser code or WebSocket URLs. Per-person sessions and short-lived connection tickets remain work in #663. Keep unused terminal services disabled.
Use private host configuration for credentials, root paths and service URLs. Existing root variables include MIADI_CHRONICLE_ROOT, MIADI_STUDIO_DIR, MIADI_IDENTITY_DIR and MIADI_CHRONICLE_MW_URL. Empty examples do not disable existing code fallbacks. Structured workspace mappings and runtime mounts also require review; moving a path into an environment variable does not establish access control.
Keep credentials, private records and detailed audit evidence outside Git, Pages, package outputs and all artifact viewer roots. MIADI_VIEW_ROOTS configures extra roots, but the current viewer also admits the working checkout; it is not yet a publication allowlist. Publication consent and private-content checks remain open in #664.
Viewer frames and asset responses now sandbox active documents into an opaque origin. This can affect modules, forms, popups and integrations that assumed application-origin access. Validate representative stories and media; do not restore same-origin privileges to repair compatibility. A separate artifact origin and explicit publication policy remain tracked in #652.
Build and test from an isolated checkout. The targeted suite is node --test tests/security-hardening-657.test.cjs; it uses fixtures, not the live Chronicle store. Its route matrix fails when a route file neither calls a gate nor is named as a public exception with its reason. node scripts/ops/miadi-doctor.mjs checks the loaded configuration without printing values. Before public rollout, verify intended and denied access through local/direct, VPN and public proxies, then record the deployed commit and service configuration without secret values.
Historical credential revocation is tracked in #661, and dependency upgrades in #666. Source containment and enabled GitHub scanners do not complete those tasks.