Security model
malac is an agent that edits files and runs commands as your user. Its safety features decide what it may do without asking you; they are not a sandbox. This page lists what each layer does, so you can decide how much to trust a given setup.
Permissions
Section titled “Permissions”- Every tool call is checked against the permission mode and rules before it runs. Reading, searching, memory and delegation never ask; edits and commands ask unless the mode or an allow rule says otherwise.
- Deny rules are checked first and apply in every mode, autopilot included.
- Shell commands are split on
&&,||,;,|and newlines, and every segment must be allowed, so a harmless prefix cannot smuggle in a second command. - “Always” answers last for the session only and are generalized to the program (
bash(cargo *)), not to the shell.
What rules do not do: they match the text of a call, not its effect. An agent can write a script and run it, or reach the network through a tool you allowed. In autopilot, assume the agent can do anything your user can. Use autopilot in repositories you can restore, ideally in a container or a dedicated machine for unattended runs.
Cloned repositories
Section titled “Cloned repositories”A repository can contain a .malac/config.toml. To keep “clone and run malac” safe, a project file cannot set mode, providers, mcp, control, permissions, memory, web, update, daemon, remote or profiles. malac ignores those keys and prints a warning. The first five could run programs or widen permissions; memory, web, update, daemon and remote could, for example, point memory recall at another host with a key from your environment as its token, or open the daemon to other devices and start a tunnel; and a project profile could carry any of these into --profile. Only trust_project_config = true in your user config lifts this, for every project, so leave it off unless you trust every repository you work in.
A project can still contribute:
- other configuration keys, such as
model,small_model,[models.…],[agents]and[ui], - instruction files in any agent’s format, agent types, skills, slash commands, project memories and
.malac/MALAC.md, which become part of the prompt, - a
.malac/plugins.tomlthat enables plugins: their skills and commands load, but their hooks and MCP servers stay off until you approve them on your machine (see Plugins).
Instructions in a repository can steer the model like any text it reads, and the permission checks are what stand between them and your machine. In a repository you don’t trust, read its .malac/ directory and instruction files first, and stay in ask mode.
Secrets
Section titled “Secrets”malac provider add --api-key-stdinand theset_api_keytool write keys to~/.malac/credentials.tomlwith mode 0600.malac_settingsreports which providers have a key, never the key.- Prefer
api_key_envandtoken_env, which keep secrets in your environment. - Everything you type is in the session transcript. A key pasted into a prompt is stored in
~/.malac/sessions/<id>.jsonland sent to the model. Delete the session if that happens. - Commands the agent runs inherit your environment, including any keys in it.
Your data
Section titled “Your data”- Transcripts (
~/.malac/sessions) and memories (Markdown files) stay on your machine, readable and deletable. - Prompts, file contents the agent reads and tool results go to the model provider you configured.
- With vector memory, Milvus stores embeddings plus each memory’s name, scope and project path; the text stays in the files. The embedding provider receives the memory text.
The daemon and the web UI
Section titled “The daemon and the web UI”The daemon runs as your user and holds every interactive session, so it can do whatever those sessions can. It serves the web UI and its API:
- Bound to
127.0.0.1by default, and only local requests get in: from a loopback address, naming a loopback host, with no proxy headers. Requests from other machines, through tunnels and proxies, or from pages that rebind their name to this machine (DNS rebinding) are refused. - Every API call and the event stream need a token. The master token, in
~/.malac/daemon.tokenand~/.malac/daemon.json(both readable only by you), works on local requests only. Deletedaemon.tokento rotate it. - Remote access is opt-in (
web.remote = trueor--remote). Other devices pair with a one-time code, valid ten minutes for one device, for a token of their own. Device tokens are stored hashed in~/.malac/devices.json, compared in constant time, and revoked one by one, which closes the device’s connections. After ten wrong codes, every open code is withdrawn. - Remote traffic is plain HTTP unless a tunnel or proxy adds TLS. On networks you don’t control, use SSH, Tailscale or a TLS reverse proxy. Cloudflare and ngrok tunnels terminate TLS at their edge and can see the traffic.
- A paired device can do everything you can: run prompts, answer approvals, change settings, pair and revoke devices, start tunnels. Pair only devices you own, and revoke lost ones.
- Any client can answer a permission request for any agent; the first answer wins.
- The daemon keeps the environment it was started with, including any API keys in it, until it restarts.
Control service
Section titled “Control service”malac-control servebinds to127.0.0.1and requires a token (random unless you set one). The discovery file~/.malac/control.json, which holds the token, is readable only by you and removed when the service stops.- Desktop tools act with the macOS permissions granted to the app that started the control service: the terminal or editor that started the daemon, or the terminal running
malac-control serve;malac-control permissionsnames it. Browser tools run in separate Chrome profiles under~/.malac/browser, so they never touch your everyday profile, but they do have whatever you logged into inside them. - Read-only tools (screenshots, snapshots, listings) never ask. Clicking, typing, navigation and
browser_evalfollow the permission mode. Denycomputer_*orbrowser_evalif you don’t want them at all.
Plugins
Section titled “Plugins”Plugins are code from someone else. Installing one runs nothing; enabling one whose hooks, MCP servers or scripts run code asks you first and lists what it runs (--yes approves). Approvals are recorded per plugin on your machine, never in a project file, and an update that adds hooks or servers leaves them off until you approve again. When the agent enables a plugin through malac_configure, it asks you even in autopilot. Once approved, hooks run as your user, like any command; read malac plugin show <plugin> before you approve. Plugin scripts run through bash, under your permission mode and rules.
MCP servers
Section titled “MCP servers”A stdio MCP server is a program malac starts with your environment; a remote one receives your tool calls. Only add servers you trust. Their tools are Execute tools unless the server marks them read-only, so they ask in ask and edits mode.
Subagents
Section titled “Subagents”Subagents share the session’s permission policy and ask through the same prompts, labelled with their name. read_only limits a subagent to Safe tools, and every subagent it starts is read-only too, so it cannot get around the limit by delegating. Agent types with a tools list are limited to those tools.
Updates
Section titled “Updates”malac update and the install script download from GitHub releases over HTTPS and check each archive against the release’s SHA256SUMS. The checksum file comes from the same release, so it protects against corrupted downloads, not against a compromised release. Binaries are swapped with an atomic rename, and a lock prevents concurrent updates.
Reporting a vulnerability
Section titled “Reporting a vulnerability”Please report security issues privately to the maintainers through GitHub rather than in a public issue.
malac is created by lobirus and released under the MIT license. About malac