Security¶
Threat model, secrets management, and supply-chain considerations for Machina deployments.
Threat Model¶
Trust Boundaries¶
┌─────────────────────────────────────────────────────┐
│ Machina Process │
│ ┌──────────┐ ┌───────────┐ ┌──────────────────┐ │
│ │ MCP │ │ Connector │ │ DocumentStore │ │
│ │ Transport│──│ Layer │──│ (RAG) │ │
│ └────┬─────┘ └─────┬─────┘ └────────┬─────────┘ │
└───────┼──────────────┼────────────────┼─────────────┘
│ │ │
MCP Client CMMS / IoT Ingested Documents
(trusted?) (trusted) (untrusted content)
Transport: stdio¶
Trust level: The MCP client is a local process on the same machine.
Risk: Any local process can connect. There is no authentication — stdio mode grants full CMMS write access to whoever invokes the process.
Single-user environments only
stdio mode is designed for local development and single-user IDE integrations (Claude Desktop, Cursor). Do not use it in multi-user or server environments. Use streamable-http with bearer token auth instead.
Transport: streamable-http¶
Trust level: The MCP client authenticates with a static bearer token.
Risk profile:
- Token compromise gives full CMMS read/write access for the compromised client identity.
Rotate tokens immediately if leaked. Tokens are mapped to client IDs in
MACHINA_MCP_TOKENS_JSONfor audit trails. - Network exposure: Bind to
127.0.0.1unless behind a reverse proxy with TLS. Machina does not terminate TLS itself.
Mitigations:
- Generate strong tokens:
openssl rand -hex 32 - Use
MACHINA_MCP_TOKENS_JSON(not the legacy comma-separated format) to map each token to a named client identity. - Place behind a reverse proxy (nginx, Caddy, Envoy) for TLS termination.
- Restrict network access via firewall rules to known MCP client IPs.
DocumentStore (RAG Ingestion)¶
Trust level: Ingested documents are untrusted content.
Risk: A malicious document could contain prompt-injection payloads that attempt to manipulate the LLM into unauthorized actions (e.g., "ignore previous instructions and create a work order for...").
Mitigations:
- Machina's prompt templates include injection-defense preambles.
- Sandbox mode (
MACHINA_SANDBOX_MODE=true) prevents any write from executing — writes are logged but not sent to the CMMS. - Review ingested documents before adding them to the vector store in production.
Source-Path Sanitisation at the LLM Boundary¶
Risk: The raw DocumentChunk.source returned by a connector is typically an
absolute filesystem path (e.g. C:\Users\foo\bar\manual.md or
/var/data/manuals/pump.md). Passing it verbatim into the LLM-visible context
or the search_documents tool result exposes the host's filesystem layout —
any model asked to cite a source will repeat the path, sometimes prefixed with
the user account name. This is a deterministic leak rooted in the framework's
own payload, not an LLM hallucination.
Mitigations (always-on):
- The two runtime boundaries that build LLM-visible document payloads
(
Agent._gather_contextand thesearch_documentstool result) pass every source throughagent.prompts._safe_source, which strips directory components from path-like strings and passes through opaque IDs and URLs. format_document_resultsinvokes_safe_sourceagain as defence in depth, so any future call site that forgets the sanitisation upstream is still protected at the prompt-formatting layer.- The system prompt's Guideline 8 explicitly forbids the LLM from disclosing absolute file paths, directory structures, database schemas, or system architecture. This is a backstop, not the primary defence — the primary defence is to never hand those values to the LLM in the first place.
- The raw
chunk.sourceremains available for non-LLM consumers (logs, trace files protected separately byActionTracer.redacting_dump_json). See Traces / Redaction for the parallel mechanism on the trace export side.
Trace JSONL Files¶
Trust level: Internal diagnostic data.
Risk: Trace files may contain:
- Tool call arguments (asset IDs, work order descriptions)
- LLM cost data
- Conversation IDs
They do not contain raw LLM prompts or API keys (redacted by the ActionTracer).
Mitigations:
- Store traces in a directory with restricted permissions (
chmod 750). - The trace exporter supports field redaction — configure it to strip sensitive fields before shipping to external systems.
- Rotate and archive traces periodically.
Secrets Management¶
Baseline: Environment Variables¶
The simplest approach — secrets live in an environment file:
# /etc/machina/machina.env (systemd)
# chmod 600, owned by root
OPENAI_API_KEY=sk-...
MACHINA_MCP_TOKENS_JSON={"token1": "client-a", "token2": "client-b"}
MACHINA_CMMS_PASSWORD=...
For Docker, use .env with docker compose:
Advanced: External Secret Stores¶
For production deployments with stricter compliance requirements:
HashiCorp Vault / Azure Key Vault: Wrap the Machina start command in a script that fetches secrets and injects them as environment variables:
#!/bin/bash
export OPENAI_API_KEY=$(vault kv get -field=key secret/machina/openai)
export MACHINA_CMMS_PASSWORD=$(vault kv get -field=password secret/machina/cmms)
exec /opt/machina-venv/bin/python -m machina.mcp \
--transport streamable-http \
--config /etc/machina/config.yaml
Update the systemd unit's ExecStart to point to this wrapper script.
SOPS for GitOps:
Encrypt your .env or config.yaml with SOPS
and decrypt at deploy time:
What to Protect¶
| Secret | Where used | Rotation impact |
|---|---|---|
OPENAI_API_KEY / ANTHROPIC_API_KEY |
LLM provider calls | Restart required |
MACHINA_MCP_TOKENS_JSON |
MCP client auth | Restart required; coordinate with MCP clients |
MACHINA_CMMS_PASSWORD |
CMMS connector | Restart required |
| OPC-UA certificates | IoT connector | Restart required; re-establish subscriptions |
Supply Chain¶
Dependencies¶
Machina's Python dependencies are declared in pyproject.toml with version constraints.
Review the dependency tree before deploying:
Container Image¶
The Docker image (deploy/docker/Dockerfile) uses a multi-stage build with
python:3.11-slim as the base. To pin the base image digest:
Vulnerability Scanning¶
# Scan Python dependencies
pip-audit --requirement requirements.txt
# Scan container image
docker scout cves machina:latest
# or
trivy image machina:latest
Hardening Checklist¶
- [ ] Use streamable-http transport (not stdio) in multi-user environments
- [ ] Generate unique MCP tokens per client with
openssl rand -hex 32 - [ ] Map tokens to client identities in
MACHINA_MCP_TOKENS_JSON - [ ] Place behind a TLS-terminating reverse proxy
- [ ] Restrict
/etc/machina/machina.envtochmod 600 - [ ] Enable sandbox mode during initial deployment (
MACHINA_SANDBOX_MODE=true) - [ ] Restrict trace file directory permissions (
chmod 750) - [ ] Review documents before ingesting into DocumentStore
- [ ] Run
pip-auditor equivalent in CI - [ ] Pin the Docker base image digest in production builds