Security
What leaves your machine, what an agent can reach, and where the boundaries end.
What leaves the machine
The results of tool calls, and nothing else. Your repository is not uploaded, cloned or indexed. A file's contents cross the network only when an agent reads that file, and only as far as the client that asked.
The audit log records what ran and how it ended, never arguments or output. It knows that run_command was called and that it failed; it does not know the command.
Nothing dials in
The CLI opens the connection outward and holds it. There is no listening socket on your machine, no port to forward, and no tunnel. Revoking a machine from the dashboard closes its connection immediately rather than at the end of whatever it was doing.
Projects are isolated at the token
Each project is a separate OAuth resource, so a token minted for one is not accepted at another. Ownership is checked against the database as well, so there are two independent checks rather than one, and an agent connected to one project's URL has no way to name another: the project comes from the path, never from anything the client sends.
The account URL, https://exeora.dev/mcp, is a separate OAuth resource of its own, and its token is refused at every project URL just as a project's token is refused there. What it does not do is decide the project from the path, so the boundary moves to the consent screen: you tick which projects it may reach, and it reaches those and nothing else. Ticking one gives the same reach as a project URL. Which of the ticked projects a call lands in is state the agent can change, and that is the whole of the difference.
A client cannot widen that by asking. If a request names both URLs at once, the project URL wins and you are shown the screen that names the project, so the consent you give and the token you hand out cannot describe different things.
Every path is confined
Paths are resolved and checked against the project root before anything touches the disk. Absolute paths, and anything climbing out with .., are refused rather than resolved. Symlinks are resolved before the check, so a link pointing outside the project does not become a way through it.
Policy is checked twice
The gateway checks it because it is the only side holding the account's setting, and because an older CLI would ignore a field it does not know. The executor checks it because it is the authority on the machine, and the only side that can read a project's own exeora.toml. Both run the same code, which is the only way "checked twice" is worth more than "checked once".
Nothing is queued
With no executor connected, a call fails at once with LOCAL_EXECUTOR_OFFLINE, and every call carries an absolute deadline the executor re-checks on arrival. A command landing hours after it was asked for, when a laptop wakes up, is the hazard this refuses to accept.
The same rule runs the other way. When the client hangs up or the connection drops, the CLI kills the command's whole process group, and processes started with start_command die with the connection. Nothing keeps working once there is nobody left to read the answer.
Where the boundaries end
Worth being plain about, because a boundary you misjudge is worse than one you know:
- A project is a directory, not a sandbox. A command running inside it runs as your user, with your environment and your network. It can reach anything that user can reach. The confinement is on the paths the tools take, not on what a program does once it starts.
- An allow list with
shell = trueis a suggestion. Turn it on only for a project you would have left open regardless. - A new project allows everything. Nothing is restricted until you restrict it.
- Confirmation only reaches a person who is there. A machine with no terminal and nobody watching the dashboard will refuse the call after ninety seconds, which is safe but is not the same as being asked.
Reporting something
Mail hello@exeora.dev, the same address as everything else. Please do not open it anywhere public first.