🔒 Security¶
Most connection types (SSH, SSH Command, Docker over SSH, and Docker over SSH Command) reach the solver over a network, so the add-on’s security story is mostly the SSH endpoint’s security story. This page collects the things you need to know before pointing it at a host you do not fully control, or a host that is reachable from the wider internet.
If you use Local or Windows Native the network-attacker sections below do not apply: the solver is a child process on your own machine and no TCP socket leaves it. Skip to Code execution risk: MCP and Credential files on disk.
Where the Trust Boundaries Are¶
The diagram on the Connections page shows the transport topology. The trust boundaries that matter for security are:
Boundary |
What crosses it |
Protection |
|---|---|---|
Blender workstation -> remote solver host |
SSH session (paramiko) |
SSH key auth + SSH encryption |
SSH session -> |
|
Stays inside the SSH tunnel; not a separate network hop |
Blender workstation <-> local solver |
UNIX loopback TCP socket |
No encryption; no encryption needed (never leaves the host) |
Blender workstation <-> local MCP server |
UNIX loopback TCP socket on port |
Bound to |
The important consequence: when you run Docker-over-SSH or plain SSH,
the solver’s TCP socket never crosses an untrusted network directly.
paramiko opens a direct-tcpip channel to localhost:<server_port>
on the remote. By default server.py binds to 127.0.0.1 (loopback
only) on the remote in plain SSH, Local, and Windows Native modes, so
the SSH tunnel is the only way in. In Docker-family modes the add-on
launches server.py with --host 0.0.0.0 inside the container
because docker -p HOST:CONTAINER forwards traffic to the container’s
external interface (eth0), not loopback; external reachability of the
container is then controlled by the host-side -p mapping (see below).
SSH Authentication¶
The add-on only supports public-key authentication. There is no password field in the UI, and paramiko is never asked to try password auth. Concretely:
Provide a private key in SSH Key (Custom mode) or via
-i(Command mode). Ed25519 and RSA keys are supported; PuTTY.ppkkeys are not.The matching public key must be in the remote account’s
~/.ssh/authorized_keys.Encrypted (passphrase-protected) keys are not supported by the add-on’s paramiko integration: paramiko is invoked without a passphrase argument or prompt callback, so an encrypted key file raises an exception at connect time. Use
ssh-agent(orkeychain,pageant,gnome-keyring) to unlock the key once per login session and let paramiko pick it up through the agent, or decrypt the key file before pointing the add-on at it.Use a dedicated key for the solver host where practical, so revoking access to the solver does not require revoking access everywhere else that key is trusted.
On the server side, the usual SSH hardening rules apply and are not the
add-on’s responsibility: disable password auth in sshd_config
(PasswordAuthentication no), keep PermitRootLogin tight, and limit
authorized_keys with from=, command=, or restrict options if
the account is dedicated to the solver.
Host-Key Verification (Trust-on-First-Use)¶
Warning
The add-on accepts unknown host keys silently. It does not
consult ~/.ssh/known_hosts, and it does not honor
StrictHostKeyChecking from ~/.ssh/config. Internally, paramiko is
configured with AutoAddPolicy.
This means the very first connection to a host has no out-of-band verification: a man-in-the-middle on that first handshake can present their own key and the add-on will trust it. Mitigations:
Do the first connect from a trusted network. A home or office LAN with known routing is safer than a hotel or airport Wi-Fi for the initial handshake.
Prefer a jump host you already trust. Bring up
ssh -Lfrom a terminal (which does honorknown_hosts), then point the add-on atlocalhost:<forwarded-port>. The add-on’s weak policy now only applies to a loopback handshake, which a network attacker cannot influence.Avoid public networks for first-run on production hosts. If you have to, verify the SSH fingerprint out of band after connecting (for example, by logging in from a known-good machine and checking the remote’s
/etc/ssh/ssh_host_*_key.pub).
The add-on cannot be configured to reject unknown keys from the panel;
the tunnel-through-your-own-ssh pattern is the supported escape hatch.
Network Exposure of the Solver Port¶
server.py listens on TCP. Where that TCP socket is reachable from
depends on how the backend is deployed, not on the add-on:
Plain SSH / SSH Command.
server.pyruns in the remote user’s shell and the add-on launches it with--host 127.0.0.1, so the socket is loopback-only on the remote. The add-on reaches it through the SSH session’sdirect-tcpipchannel; nothing else on the network can connect, regardless of host firewall. If you need the port reachable from the remote’s wider network for some other tool, you must rebind it yourself (e.g. by relaunchingserver.py --host 0.0.0.0outside the add-on).Docker / Docker over SSH. Inside the container the add-on launches
server.py --host 0.0.0.0because docker-p HOST:CONTAINERforwards traffic to the container’s external interface (eth0), not loopback. External reachability of the host is then controlled by the-pmapping you choose: the container must publish the server port (-p 9090:9090or the equivalent in your compose file), otherwise the add-on refuses to start. The default-p 9090:9090binds to all interfaces on the Docker host, which can expose the solver to any network that reaches that host. Prefer-p 127.0.0.1:9090:9090so the publish is loopback-only; the add-on will still reach it over the SSH tunnel.Windows Native / Local. The server binds to the local machine only (loopback). No container and no host firewall change to worry about.
A quick check on the remote (or inside the container):
# On the solver host (plain SSH) or inside the container (Docker)
ss -tlnp | grep 9090
# LISTEN 0 ... 127.0.0.1:9090 ... → loopback-only (default for plain SSH / Local / Windows)
# LISTEN 0 ... 0.0.0.0:9090 ... → all interfaces (default inside Docker; host -p mapping controls external exposure)
Plain SSH now binds loopback-only by default. For Docker-over-SSH the
in-container bind is 0.0.0.0 (required for port publishing); restrict
the host-side mapping with -p 127.0.0.1:9090:9090 if you do not want
the port exposed beyond the Docker host’s loopback.
What the Add-on Does Not Support from ~/.ssh/config¶
The bundled SSH parser is intentionally minimal; several options that you might rely on for security elsewhere are silently ignored. See Supported ssh_config options for the authoritative list. The ones worth flagging here:
Option |
Consequence |
|---|---|
|
Ignored. See Host-key verification. |
|
Ignored. |
|
Ignored. Bring up the jump yourself with |
|
Ignored. paramiko will try the configured key, then every key the agent offers, then any |
|
Ignored. paramiko picks the auth method. |
|
Ignored as an |
If your environment depends on any of these for its security posture
(bastion-only access, certificate-gated auth, pinned host keys), bring
up ssh -L yourself from a terminal so that the system ssh binary
handles the sensitive part of the connection and the add-on only talks
to localhost.
Code Execution Risk: MCP¶
The bundled MCP server exposes
run_python_script and execute_shell_command by design. There is
no sandbox, no allowlist, and no authentication. The protections are
purely network-scoping:
The MCP server binds to
localhostonly (see Connections ports). Do not forward the MCP port overssh -R,ngrok,gh codespaces, or any reverse proxy unless the machine is disposable.Any process on the Blender machine can reach the MCP port. Treat local-user isolation as your security boundary: a malicious local user already owns the Blender session.
LLM outputs wired into
run_python_scriptare effectively shell on your machine. Always review the agent’s tool calls before approving them; see MCP Security.
Credential Files on Disk¶
The add-on stores connection details in plain-text TOML connection profiles. Profile files contain hostnames, ports, usernames, container names, and paths to private keys; they do not contain the keys themselves or any passphrases.
Keep the profile file readable only by your user (
chmod 600 connections.tomlon Unix). The add-on does not enforce this.When sharing a profile with teammates (check-in, chat, paste), strip the
usernameandkey_pathfields first. The host + container + port fields are usually fine; the identity fields are not.The private key file itself should also be mode
600and owned by your user (chmod 600 ~/.ssh/id_ed25519). paramiko does not load world-readable keys silently, but it does not refuse them either.
Logs and Artifacts¶
server.log and progress.log on the remote capture the solver’s
stdout and a structured run log. They can contain:
Remote file paths under the project directory.
Scene metadata (object names, frame counts, parameter values).
Tracebacks from the solver, including absolute paths on the host.
They do not contain your SSH key, Blender credentials, or the raw geometry. If the remote is shared, review the project directory’s permissions if these logs are sensitive.
The local reload and MCP servers log to Blender’s console (the terminal that launched Blender, or Blender’s Python console), not to disk.
Quick Checklist Before Connecting to an Untrusted Network¶
Use an Ed25519 key dedicated to the solver host.
Make sure the key is either unencrypted-but-safeguarded or loaded into
ssh-agent.Bring up a trusted tunnel from a terminal (
ssh -L 2222:gpu01.example.com:22 bastion.example.com) rather than letting the add-on dial the hostile network directly.Point the add-on at
localhost:2222, leaving the weak host-key policy applied only to loopback.On the remote, verify the server port is not reachable from the outside. With plain SSH the add-on now binds
server.pyto127.0.0.1so loopback-only is the default; confirm withss -tlnp | grep 9090(you should see127.0.0.1:9090, not0.0.0.0:9090).If you use Docker-over-SSH, publish the host-side port as
127.0.0.1:9090:9090(the in-container bind is0.0.0.0by necessity, but the host mapping can still be loopback-only).Keep the MCP port on
localhost. Do notssh -Rit, do not proxy it, do not expose it to an LLM that executes arbitrary network tools without review.