A step-by-step checklist to maximize the security of your Comis installation
Comis is secure by default — audit logging, input scanning, output guarding, and many other protections are active from the moment you start the daemon. But you can make your installation even stronger by following this hardening checklist. Each item below addresses a specific security concern, ordered by priority so you tackle the most important changes first.
Before working through the checklist manually, run the built-in security audit to see where your installation stands:
comis doctor
This command checks 5 security categories and reports findings with severity levels (critical, warning, info) and specific remediation advice. Each finding tells you exactly what to fix and how. Run it again after making changes to verify your progress.
The security audit can automatically fix some findings. Follow the suggested remediation commands in the output.
These items address the most significant security risks. Complete them before exposing your installation to any network.
1
Set file permissions
Your config file contains sensitive settings and your data directory holds databases and secrets. Restrict access so only your user account can read them:
chmod 600 ~/.comis/config.yaml # Only owner can read/writechmod 700 ~/.comis/ # Only owner can access directory
Why: Prevents other users on the system from reading your configuration or data files. On a shared server, this is essential.Verify:ls -la ~/.comis/config.yaml shows -rw-------.
2
Remove plaintext secrets from config
If your config.yaml contains raw API keys, migrate them to environment variables or the encrypted store:
# Bad: plaintext secret in configproviders: openai: apiKey: sk-abc123...# Good: reference an environment variableproviders: openai: apiKey: ${OPENAI_API_KEY}
Or better yet: set up the encrypted secrets store for production-grade secret management.Why: Config files may be backed up, shared, or accidentally committed to version control. Plaintext secrets in config are the most common security mistake.Verify:comis doctor reports no “plaintext secret” findings.
3
Configure gateway authentication
If you expose the HTTP gateway (for the web dashboard, JSON-RPC, or WebSocket), always require authentication tokens. Each token entry needs a unique id, a secret of at least 32 characters, and the scopes it is allowed to use:
Why: Without authentication, anyone who can reach the gateway can control your agents, read your data, and modify your configuration.Verify:curl http://localhost:4766/health returns 200, but curl http://localhost:4766/api/agents returns 401.
4
Bind to localhost or enable TLS
If the gateway is only for local use (web dashboard on the same machine), bind to localhost:
~/.comis/config.yaml
gateway: host: "127.0.0.1" port: 4766
If you need remote access, enable TLS to encrypt traffic:
Why: Without TLS, traffic (including auth tokens) is sent in plain text over the network. Anyone on the same network can intercept it.Verify:comis doctor reports no “gateway exposure” findings.
These items strengthen your security posture significantly. They are important for any production deployment.
1
Enable the encrypted secrets store
Migrate from .env files to the encrypted store for production:
~/.comis/config.yaml
security: storage: encrypted
The encrypted store uses AES-256-GCM encryption at rest, protecting your secrets even if someone gains access to the data directory. This is the default backend.See Secrets for the step-by-step setup procedure, including master key generation and importing existing secrets.Why: .env files store secrets in plain text. The encrypted store ensures secrets cannot be read without the master key.
2
Configure per-agent secret access
Restrict each agent to only the secrets it needs using glob patterns:
See Secrets: Per-Agent Access for details.Why: Follows the principle of least privilege. If an agent is compromised, it can only access the secrets it was explicitly granted — not every secret in the store.
3
Enable the approval workflow
Require human approval for destructive agent actions:
~/.comis/config.yaml
approvals: enabled: true defaultMode: auto
This pauses execution when an agent attempts a destructive action (like deleting a file) and waits for your approval before proceeding. If you do not respond within the timeout, the action is automatically denied.See Approvals for the full configuration including custom rules and timeout settings.Why: Prevents agents from taking irreversible actions without your knowledge. This is especially important for agents with broad tool access.
4
Review tool policy profiles
Switch agents from the default full profile to a more restrictive one:
~/.comis/config.yaml
agents: customer-support: skills: toolPolicy: profile: messaging # Only communication tools code-assistant: skills: toolPolicy: profile: coding # Only development tools
See Tool Policy for all profiles and custom rules.Why: Limits the blast radius if an agent is compromised. A messaging agent does not need file system access, and a coding agent does not need fleet management tools.
5
Verify audit logging is enabled
Confirm that audit logging is active (it should be by default):
~/.comis/config.yaml
security: auditLog: true
Why: Audit logs are essential for detecting and investigating security incidents. Without them, you have no visibility into what your agents have done.Verify: Check the Security dashboard Audit Log tab for recent events.
These items provide additional hardening for environments with strict security requirements.
1
Verify exec sandbox is active
The exec sandbox wraps shell commands in an OS-level namespace so agents
cannot access files outside their workspace. On Linux, this requires
bubblewrap:
# Check if bubblewrap is installedwhich bwrap# Install if missing (Debian/Ubuntu)sudo apt install bubblewrap
On macOS, sandbox-exec is built in — no installation needed.Verify your config does not disable the sandbox:
~/.comis/config.yaml
agents: my-agent: skills: execSandbox: enabled: "always" # default -- do not set to "never"
Why: Without the exec sandbox, agents can bypass file tool path
restrictions by using exec cat instead of the read tool. The
sandbox prevents this at the kernel level.Verify: Check logs for "Exec sandbox provider: bwrap" (Linux) or
"Exec sandbox provider: sandbox-exec" (macOS) at daemon startup.
2
Configure Node.js permission model
For maximum process isolation, enable the Node.js permission model to restrict what the Comis process itself can access:
Why: Restricts the Node.js process itself to only the file paths and network hosts you specify. Even if an attacker achieves code execution, they cannot access files or hosts outside the allowed list.
This is a restrictive setting. Test thoroughly before enabling in production — some features may need additional paths or hosts. The default is security.permission.enableNodePermissions: false.
Enabling enableNodePermissions: true also disables the fd-based fs API family (fsync, fchmod, fchown) at the Node.js level. Under --permission, encrypted-mode credential file writes are best-effort durability (fsync is skipped) and trace/session file permissions (fchmod) are best-effort. Comis guards all call sites via isFsyncDisabledByPermissionModel, so the daemon will not crash, but power loss between write and rename could leave a corrupt credential file. This behavior is Linux-only (production systemd deploys). See Node Permissions — fd-API disablement for full detail.
3
Set up CORS restrictions
If the web dashboard is accessed from a specific domain, restrict CORS to prevent unauthorized web pages from making API requests:
~/.comis/config.yaml
gateway: corsOrigins: - "https://your-domain.com"
Why: Without CORS restrictions, any web page open in a user’s browser could potentially make API requests to your gateway if the user is on the same network.
4
Review plugin hook registrations
If you use custom plugins, review which hooks they register. Each hook point has security implications — a plugin registered on the beforeToolCall hook can intercept and modify tool invocations, while a plugin on beforeResponse can alter agent output.Why: Malicious or poorly written plugins can intercept and modify messages, tool calls, or agent behavior. Only install plugins from trusted sources.Verify: Review your plugin configuration and the hooks each plugin uses.
5
Configure browser sandboxing
If agents use browser tools, ensure sandboxing is properly configured. Browser tools provide powerful web access capabilities, which also means they are a potential vector for data exfiltration or accessing internal services.Why: Browser tools can access the web, which creates opportunities for both SSRF attacks and data exfiltration. Proper sandboxing ensures browser actions are constrained.Verify: Check your comis doctor output for specific browser security recommendations.What the installer does for you: When the daemon is installed with --with-browser, --with-xvfb, or --with-cloakbrowser, the systemd unit is written with two layers of filesystem isolation around the browser binary:
Layer
What it does
Browser-tool specifics
Kernel sandbox (ReadWritePaths=)
Bind-mounts the rest of the host filesystem read-only. The browser process can write only to the listed paths.
~/.config/comis/browser (profile dir) plus a small set of binary-specific paths — ~/.config/google-chrome + ~/.local/share/applications for stock Chrome, or ~/.cloakbrowser + ~/.config/chromium for CloakBrowser (tighter — no mimeapps write).
Node --permission model (--allow-fs-write=)
Independently constrains what the Node daemon process can write, even before kernel checks run.
Same paths as ReadWritePaths, kept in lockstep so the two layers don’t drift.
Both are emitted by render_systemd_unit in install.sh and rendered into /etc/systemd/system/comis.service. The unit is checksummed and refuses to overwrite hand edits, so once you’ve audited the paths they stay stable across upgrades.For the --with-xvfb variant, the companion comis-xvfb.service unit runs as the same user, joins the daemon’s /tmp namespace via JoinsNamespaceOf=, and exposes Xvfb on a Unix socket only (-nolisten tcp) — no network surface added.What it does not do: the daemon does not block what URLs the browser navigates to (beyond the always-on SSRF guard against private IPs, loopback, and cloud metadata endpoints). If you need URL allowlisting, layer that at the network egress level (egress-logging chain + outbound firewall rules).
6
Review SSRF attack surface
Review which agents have access to web-fetching tools. SSRF protection is always active — Comis blocks requests to private IPs, loopback addresses, and cloud metadata endpoints — but reducing the number of agents with web access reduces your overall attack surface.
Why: Fewer agents with web access means fewer potential SSRF vectors. Even with built-in SSRF protection, defense in depth means reducing unnecessary exposure.
7
Rotate the SECRETS_MASTER_KEY periodically
Treat the master key like any other production credential — rotate it on
a schedule (every 90 days is a reasonable cadence) and after any
suspected exposure. The recommended flow:
# 1. Generate the new keyopenssl rand -hex 32 > /tmp/new-master-key.hex# 2. Re-encrypt every secret under the new keySECRETS_MASTER_KEY="$(cat /tmp/new-master-key.hex)" \ node packages/cli/dist/cli.js secrets rotate \ --old-key="$OLD_SECRETS_MASTER_KEY"# 3. Atomically swap the env var in your secret store, restart the daemonpm2 restart comis
Why: A compromised master key gives an attacker every secret in the
encrypted store. Periodic rotation limits the blast radius and ensures
your operational runbook actually works before you need it.
8
Lock down the email allowlist
If you enable the email channel, set allowMode: "allowlist" and list
every legitimate sender. The default closed posture rejects any sender
not on the list:
~/.comis/config.yaml
channels: email: allowMode: "allowlist" # never use "open" in production allowFrom: - "alice@example.com" - "bob@example.com" - "ops@example.com"
Comis additionally auto-detects bulk and automated mail (Auto-Submitted
headers, Precedence, List-Unsubscribe, noreply addresses) and rejects
those even if the sender is listed.Why: Email is the easiest prompt-injection vector. An open allowlist
on a public address is equivalent to letting the internet drive your
agent.
Remember to launch the daemon with the matching --allow-net=... flag
— the config field alone is a declaration, not enforcement. See
Node Permissions.Why: Even with SSRF protection on every web tool, an
egress allowlist provides a second layer that limits exfiltration to
known good hosts.
After completing the checklist, run the security audit again to confirm your changes:
comis doctor
A fully hardened installation should show no critical or warning findings. Info-level findings are informational and typically do not require action.Review the output carefully. Each finding includes:
Severity — Critical, warning, or info
Description — What was found
Remediation — Specific steps to fix the finding
Category — Which security area the finding relates to
Security hardening is not a one-time task. Re-run comis doctor periodically, especially after configuration changes or upgrades. New versions may introduce additional security checks.
Comis can scan file writes for secret-shaped values and warn or block before a live API key is committed to disk in cleartext. Configure security.writeSecretGuard (default: warn) — see Secrets — Output Guard for Secret Egress for configuration options and tradeoffs.